如果你向Executor提交了一个批处理任务,并且希望在它们完成后获得结果,怎么办呢?

为此你可以保存与每个任务相关联的Future,然后不断地调用 timeout为零的get,来检验Future是否完成。这样做固然可以,但却相当乏味。幸运的是,还有一个更好的方法:完成服务 (Completion service)。

CompletionService整合了Executor和BlockingQueue的功能。

你可以将Callable任务提交给它去执行,然 后使用类似于队列中的take和poll方法,在结果完整可用时获得这个结果,像一个打包的Future。 ExecutorCompletionService是实现CompletionService接口的一个类,并将计算任务委托给一个Executor。

ExecutorCompletionService的实现相当直观。它在构造函数中创建一个BlockingQueue,用它去保持完成的结果。 计算完成时会调用FutureTask中的done方法。

当提交一个任务后,首先把这个任务包装为一个QueueingFuture,它是 FutureTask的一个子类,然后覆写done方法,将结果置入BlockingQueue中,take和poll方法委托给了 BlockingQueue,它会在结果不可用时阻塞。

直接看demo:

package javademo;

import java.util.Random;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.Callable;

import java.util.concurrent.CompletionService;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorCompletionService;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

import java.util.concurrent.LinkedBlockingQueue;

/***

* 两钟方式出来线程运行结果

* @author think

*

*/

public class CompletionServiceTest {

public static void main(String[] args) throws Exception {

CompletionServiceTest cst = new CompletionServiceTest();

cst.count1();

cst.count2();

}

/***

* 使用阻塞容器保存每次Executor处理的结果,在后面进行统一处理

* @throws Exception

*/

public void count1() throws Exception{

ExecutorService exec = Executors.newCachedThreadPool();

BlockingQueue<Future<Integer>> queue = new LinkedBlockingQueue<Future<Integer>>();

for(int i=0; i<10; i++){

Future<Integer> future =exec.submit(getTask());

queue.add(future);

}

int sum = 0;

int queueSize = queue.size();

for(int i=0; i<queueSize; i++){

sum += queue.take().get();

}

System.out.println("总数为:"+sum);

exec.shutdown();

}

/***

* 使用CompletionService(完成服务)保持Executor处理的结果

* @throws InterruptedException

* @throws ExecutionException

*/

public void count2() throws InterruptedException, ExecutionException{

ExecutorService exec = Executors.newCachedThreadPool();

CompletionService<Integer> execcomp = new ExecutorCompletionService<Integer>(exec);

for(int i=0; i<10; i++){

execcomp.submit(getTask());

}

int sum = 0;

for(int i=0; i<10; i++){

//检索并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则等待。

Future<Integer> future = execcomp.take();

sum += future.get();

}

System.out.println("总数为:"+sum);

exec.shutdown();

}

/**

* 得到一个任务

* @return Callable

*/

public Callable<Integer> getTask(){

final Random rand = new Random();

Callable<Integer> task = new Callable<Integer>(){

@Override

public Integer call() throws Exception {

int i = rand.nextInt(10);

int j = rand.nextInt(10);

int sum = i*j;

System.out.print(sum+"\t");

return sum;

}

};

return task;

}

}

  1. import java.util.Random;
  2. import java.util.concurrent.BlockingQueue;
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.CompletionService;
  5. import java.util.concurrent.ExecutionException;
  6. import java.util.concurrent.ExecutorCompletionService;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. import java.util.concurrent.Future;
  10. import java.util.concurrent.LinkedBlockingQueue;
  11. public class Test17 {
  12. public static void main(String[] args) throws Exception {
  13. Test17 t = new Test17();
  14. t.count1();
  15. t.count2();
  16. }
  17. //使用阻塞容器保存每次Executor处理的结果,在后面进行统一处理
  18. public void count1() throws Exception{
  19. ExecutorService exec = Executors.newCachedThreadPool();
  20. BlockingQueue<Future<Integer>> queue = new LinkedBlockingQueue<Future<Integer>>();
  21. for(int i=0; i<10; i++){
  22. Future<Integer> future =exec.submit(getTask());
  23. queue.add(future);
  24. }
  25. int sum = 0;
  26. int queueSize = queue.size();
  27. for(int i=0; i<queueSize; i++){
  28. sum += queue.take().get();
  29. }
  30. System.out.println("总数为:"+sum);
  31. exec.shutdown();
  32. }
  33. //使用CompletionService(完成服务)保持Executor处理的结果
  34. public void count2() throws InterruptedException, ExecutionException{
  35. ExecutorService exec = Executors.newCachedThreadPool();
  36. CompletionService<Integer> execcomp = new ExecutorCompletionService<Integer>(exec);
  37. for(int i=0; i<10; i++){
  38. execcomp.submit(getTask());
  39. }
  40. int sum = 0;
  41. for(int i=0; i<10; i++){
  42. //检索并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则等待。
  43. Future<Integer> future = execcomp.take();
  44. sum += future.get();
  45. }
  46. System.out.println("总数为:"+sum);
  47. exec.shutdown();
  48. }
  49. //得到一个任务
  50. public Callable<Integer> getTask(){
  51. final Random rand = new Random();
  52. Callable<Integer> task = new Callable<Integer>(){
  53. @Override
  54. public Integer call() throws Exception {
  55. int i = rand.nextInt(10);
  56. int j = rand.nextInt(10);
  57. int sum = i*j;
  58. System.out.print(sum+"\t");
  59. return sum;
  60. }
  61. };
  62. return task;
  63. }
  64. /**
  65. * 执行结果:
  66. 6   6   14  40  40  0   4   7   0   0   总数为:106
  67. 12  6   12  54  81  18  14  35  45  35  总数为:312
  68. */
  69. }

Java线程之CompletionService批处理任务的更多相关文章

  1. Java线程之CompletionService

    转自:http://blog.csdn.net/andycpp/article/details/8902699 当使用ExecutorService启动了多个Callable后,每个Callable会 ...

  2. Java线程之 InterruptedException 异常

    Java线程之 InterruptedException 异常   当一个方法后面声明可能会抛出InterruptedException 异常时,说明该方法是可能会花一点时间,但是可以取消的方法. 抛 ...

  3. java 线程之executors线程池

    一.线程池的作用 平时的业务中,如果要使用多线程,那么我们会在业务开始前创建线程,业务结束后,销毁线程.但是对于业务来说,线程的创建和销毁是与业务本身无关的,只关心线程所执行的任务.因此希望把尽可能多 ...

  4. java 线程之concurrent中的常用工具 CyclicBarrier

    一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序 ...

  5. C++/Java线程之分

    JAVA线程状态图 1.C++/windows中主线程结束,其他线程必然死亡(即使调用pthread_detach解除父子关系,主线程消亡时也会导致子线程被迫关闭). ----1.1 一个进程中可以有 ...

  6. Java线程之Callable和Future

    本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果.        Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结 ...

  7. Java线程之Synchronized用法

    synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对 ...

  8. Java线程之Java内存模型(jmm)

    一.Java内存模型(jmm) 线程通信 消息传递 重排序 顺序一致性 Happens-Before As-If-Serial

  9. Java线程之Dump

    什么是线程dump Java Thread dump记录了线程在jvm中的执行信息,可以看成是线程活动的日志.Java线程转储文件有助于分析应用程序和死锁情况中的瓶颈. 如何获取线程转储文件 在这里, ...

随机推荐

  1. 小程序 wx.request ajax示例

    简单示例 https://developers.weixin.qq.com/miniprogram/dev/api/network-request.html wx.request({ method: ...

  2. Refresh Tokens: When to Use Them and How They Interact with JWTs

    In this post we will explore the concept of refresh tokens as defined by OAuth2. We will learn why t ...

  3. c语言中各种数据类型的长度

    在32位平台和64位平台上,同一种数据类型可能有不同的数据长度: 类型 32位平台 64位平台 char 1 1 short 2 2 int 4 4 long 4 8 long long 8 8 fl ...

  4. CentOS7 使用tab建补全命令

    Centos7在使用最小化安装的时候,没有安装自动补全的包,需要自己手动安装,安装下面过滤出来的包 yum -y install bash-completion 安装完毕后退出bash重新登陆生效!

  5. [转]T-SQL_面试题

    [转]T-SQL_面试题 2015-05-19 1 创建表插入数据 Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,s ...

  6. CentOS6.2下安装配置MySql

    转自:Linux学习之CentOS(十三)--CentOS6.4下Mysql数据库的安装与配置 如果要在Linux上做j2ee开发,首先得搭建好j2ee的开发环境,包括了jdk.tomcat.ecli ...

  7. C++常函数

    常函数即在类的成员函数参数列表后放置const的函数,常函数的作用是限制函数体对成员变量的修改,此外,常函数也不能调用非 常函数. #include <iostream> using na ...

  8. java中Keytool的使用总结 (加密 密钥(key)和证书(certificates))

    http://blog.chinaunix.net/uid-17102734-id-2830223.html

  9. zepto中的tap穿透

    有一个项目,浮层上是有点击的按钮,但是用tap就会穿透,触发浮层下的页面的点击事件.后来问同事和经过自己尝试,发现用click就可以解决这个问题.

  10. Java 之泛型通配符 ? extends T 与 ? super T 解惑

    简述 大家在平时的工作学习中, 肯定会见过不少如下的语句: List<? super T> List<? extends T> 我们都知道, 上面的代码时关于 Java 泛型的 ...