如果你向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. 计划任务 crontab

    1.

  2. mybatis-spring 项目简介

    mybatis-spring 主要是为了解决 spring3.0 中支持 mybatis3.0 1 mybatis-spring 主要包含以下几个部分 数据源 SqlSessionFactory Sq ...

  3. HTML十进制字符编号

    有时候写文章时,段落里引用的代码莫名的就被解释到原本的html中了,通过用一些HTML里特殊字符的编码即可回到原文,保留原格式. 字符 十进制字符编号 实体名字 说明 ! ! — 惊叹号Exclama ...

  4. atitit.seo 发帖关键词以及链接的制作.doc

    atitit.seo 发帖关键词以及链接的制作.doc 1. 关键词的获得(by cate) 1 1.1. 删除统计数量     Cartier(144)  格式 1 1.2. \(\d*\)  替换 ...

  5. etcd+calico集群的部署

    etcd单机模式 设置环境变量 1 export HostIP="192.168.12.50" 执行如下命令,打开etcd的客户端连接端口4001和2379.etcd互联端口238 ...

  6. Android之ProGuard混淆器

    ProGuard是一个压缩.优化和混淆Java字节码文件的免费的工具,它可以删除无用的类.字段.方法和属性.可以删除没用的注释,最大限度地优化字节码文件.它还可以使用简短的无意义的名称来重命名已经存在 ...

  7. ORACLE用户角色与授权

    --创建一个用户CREATE USER test_user IDENTIFIED BY test_user; --创建一个角色 CREATE ROLE connect2 ; --为角色授权 GRANT ...

  8. scala,spark练习题提高

    1.求每家公司有哪些产品 val arr3 = List("Apache" -> "Spark", "Apache" -> &q ...

  9. Android——区别DVM与JVM (2)

    区别DVM与JVM 1.首要差别 Dalvik: 基于寄存器,编译和运行都会更快些 JVM: 基于栈, 编译和运行都会慢些 2.字节码的区别 Dalvik: 执行.dex格式的字节码,是对.class ...

  10. libcurl库的编译

    终于弄懂了libcurl库的编译,记下来免得忘记. 下载地址:   libcurl库:http://curl.haxx.se/latest.cgi?curl=zip   openssl安装包:http ...