Java批处理ExecutorService/CompletionService
服务端接收一个请求,常常需要同时进行几个计算或者向其他服务发送请求,最后拼装结果返回上游。本文就来看下JDK提供几个并行处理方案,牵涉到ExcecutorService/CompletionService。要实现的场景是请求有超时限制,如果所有操作都计算完成,则全部拼装返回;否则只拼装部分完成的结果。
1.前提
//任务类,sleep一个时间代表这个计算需要的耗时,返回一个计算结果。
public class MyTask implements Callable<Integer> {
private int id;
private int time;
public MyTask(int i, int time) {
this.id = i;
this.time = time;
}
@Override
public Integer call() throws Exception {
Thread.sleep(time);
return id;
}
}
//线程池
ExecutorService threadPool = new ThreadPoolExecutor(10, 20,
60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
2.任务逐个等待
提交任务后,逐个等待结果返回。
//总共150ms超时
List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
futures.add(threadPool.submit(new MyTask(1, 60)));
futures.add(threadPool.submit(new MyTask(2, 150)));
Integer res = 0; for (int i = 0; i < futures.size(); ++i) {
try {
Integer tmp = futures.get(i).get(50 + i * 50, TimeUnit.MILLESECONDS);
res += tmp;
} catch (Exception e) {
//nothing
}
}
System.out.println(res);
打印结果为0,实际上第60ms时第一个计算已经完成,本可以返回第一个结果的。这是因为生产者和消费者一一对应,调度不当。
3.等待解耦
用一个队列来实现生产者和消费者解耦,生产者把结果放到一个队列中,消费者从队列中取结果,不按照任务提交顺序等待,只要有结果就会消耗。CompletionService就是对Executor和异步队列的封装。
CompletionService<Integer> service = new ExecutorCompletionService<Integer>(threadPool);
List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
futures.add(service.submit(new MyTask(1, 60)));
futures.add(service.submit(new MyTask(2, 150))); List<Integer> result = new ArrayList<Integer>(futures.size());
for (int i = 0; i < futures.size(); ++i) {
Future<Integer> future = service.poll(50 + i * 50, TimeUnit.MILLISECONDS);
if (null != future){
result.add(future.get());
}
}
int res = 0;
for (Integer i : result) {
res += null == i ? 0 : i;
}
System.out.println(res);
打印结果为1,即第一个计算的结果。谁先完成就取谁。
4.充分利用时间
前面两个方案为每个任务都设置了一个固定的等待时间,两者之和不超过超时限制。这没有充分利用时间,两个任务是并发互不影响的,其各自可利用的时间应该是超时时间,而不应该是两者之和为超时时间。如果第一个任务耗时140,第二个耗时60,前两个任务就只能获得第二个任务的结果。如果两者都设置超时为150,就能获得2个结果。
List<MyTask> tasks = new ArrayList<MyTask>();
tasks.add(new MyTask(1, 140));
tasks.add(new MyTask(2, 60));
List<Future<Integer>> futures = threadPool.invokeAll(tasks, 150, TimeUnit.MILLISECONDS); int res = 0;
for (Future<Integer> future : futures) {
System.out.println("isDone:" + future.isDone());
System.out.println("isCancel:" + future.isCancelled());
if (future.isCancelled()) {
continue;
}
res += future.get();
}
System.out.println(res);
打印结果是3。上述方法利用ExecutorService的invokeAll方法,该方法在所有任务都完成或等待超时时返回,超时的时候会取消还没有完成的任务,通过判断任务是否被取消来判断任务是否计算完成。
该文章说的是结果互不影响、有结果就能返回的应用场景。如果结果需要按照先后顺序进行合并,或者只需要等待一个计算完成,就不一定需要方案3了。
Java批处理ExecutorService/CompletionService的更多相关文章
- Java线程之CompletionService批处理任务
如果你向Executor提交了一个批处理任务,并且希望在它们完成后获得结果,怎么办呢? 为此你可以保存与每个任务相关联的Future,然后不断地调用 timeout为零的get,来检验Future是否 ...
- 【Java多线程】CompletionService
什么是CompletionService? 当我们使用ExecutorService启动多个Callable时,每个Callable返回一个Future,而当我们执行Future的get方法获取结果时 ...
- java批处理、MySQL批处理
e: cd MySQL\bin mysql -uroot -proot @pause MySQL批处理.bat e: cd JAVA\jdk1.8.0_77\bin javac Hello.java ...
- Java中ExecutorService和CompletionService区别
我们现在在Java中使用多线程通常不会直接用Thread对象了,而是会用到java.util.concurrent包下的ExecutorService类来初始化一个线程池供我们使用. 之前我一直习惯自 ...
- java并发编程 Executor,Executors,ExecutorService,CompletionService,Future,C
使用CompletionService获取多线程返回值 CompletionService和ExecutorCompletionService详解 Java并发编程系列之十五:Executor框架
- Java线程之CompletionService
转自:http://blog.csdn.net/andycpp/article/details/8902699 当使用ExecutorService启动了多个Callable后,每个Callable会 ...
- java中ExecutorService接口
一.声明 public interface ExecutorService extends Executor 位于java.util.concurrent包下 所有超级接口:Executor 所有已知 ...
- Java批处理操作
批量,可以大大提高众多增加.删除.变化的步伐,它是有一个非常大的数据处理效率大收益. 的"连接池"相似.事实上就是先将多次操作(增删改)打包.然后再一次发送运行 主要用到两个方法: ...
- Java 1.ExecutorService四种线程池的例子与说明
1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...
随机推荐
- c程序对于文件的处理
C 文件读写 上一章我们讲解了 C 语言处理的标准输入和输出设备.本章我们将介绍 C 程序员如何创建.打开.关闭文本文件或二进制文件. 一个文件,无论它是文本文件还是二进制文件,都是代表了一系列的字节 ...
- AsyncTask异步上传文本到服务器
服务器代码:用于接收客户端信息 package ches; import java.io.IOException; import java.io.PrintWriter; import javax.s ...
- 【APICloud】APICloud基础学习与快速入门
前言:回顾这几天学习情况,总的来说APICloud官网它的学习资料和社区还是足够了,但是我必须吐槽一句,实在是过于混乱了,视频资料文档资料它一股脑地都堆在了那里,这几天基本处于在各个地方跳转,然后现在 ...
- Codeforces CF#628 Education 8 F. Bear and Fair Set
F. Bear and Fair Set time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- XVII Open Cup named after E.V. Pankratiev. GP of SPb
A. Array Factory 将下标按前缀和排序,然后双指针,维护最大的右边界即可. #include<cstdio> #include<algorithm> using ...
- Linux内核笔记——内存管理之slab分配器
内核版本:linux-2.6.11 内存区和内存对象 伙伴系统是linux用于满足对不同大小块内存分配和释放请求的解决方案,它为slab分配器提供页框分配请求的实现. 如果我们需要请求具有连续物理地址 ...
- JQuery基本知识框架思维导图(上)
一:认识jQuery 1.window.onload与$(document).ready()的对比 2.jQuery代码风格(1:链式代码风格2:位代码添加注释) 3.jQuery对象和DOM对象(1 ...
- 简述TCP连接的建立与释放(三次握手、四次挥手)
在介绍TCP连接的建立与释放之前,先回顾一下相关知识. TCP是面向连接的运输层协议,它提供可靠交付的.全双工的.面向字节流的点对点服务.HTTP协议便是基于TCP协议实现的.(虽然作为应用层协议,H ...
- Java jvisualvm简要说明
jvisualvm能干什么:监控内存泄露,跟踪垃圾回收,执行时内存.cpu分析,线程分析... jvisualvm已经被集成在jdk1.6以上的版本中(不是jre).自身运行需要最低jdk1.6版本, ...
- 前端面试那些坑之HTML篇
HTML 1.Doctype作用?标准模式与兼容模式各有什么区别? (1).<!DOCTYPE>声明位于位于HTML文档中的第一行,处于<html> 标签之前.告知浏览器的解析 ...