如果你向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. sphinx相关文章

    sphinx配置文件详解http://yanue.net/post-129.html Sphinx+Scws 搭建千万级准实时搜索&应用场景详解 http://blog.csdn.net/pi ...

  2. spring Log4j关于No appenders could be found for logger的警告

    (spring环境下)配置Log4j时候,当启动WEB程序时,提示了如标题的警告,具体如下:log4j:WARN No appenders could be found for logger (org ...

  3. 用lambda表达式树替代反射

    本节重点不讲反射机制,而是讲lambda表达式树来替代反射中常用的获取属性和方法,来达到相同的效果但却比反射高效. 每个人都知道,用反射调用一个方法或者对属性执行SetValue和GetValue操作 ...

  4. XMLDocument转为String 摘录

    public static string FormatXmlString(string xmlString) { XmlDocument document = new XmlDocument(); d ...

  5. ruby配置相关

    1.安装ruby 方式1: yum install ruby 方式2:https://www.ruby-lang.org/en/downloads/ 使用源码安装 ./configure make m ...

  6. Python在ubuntu下常用开发包名称

    build-essential python3-setuptools python-setuptools-doc python3-all-dev python3-wheelwheel时pip支持的一种 ...

  7. PHP域名whois查询代码(数据源万网、新网)

    对于whois查询,数据来自万网.新网,数据也比较权威,需要的朋友可以参考下. 万网 whois(使用的接口为万网提供合法接口) function whois_hichina($domain) {  ...

  8. Atitit.404错误解决标准流程and url汉字中文路径404错误resin4 resin chinese char path 404 err解决

    Atitit.404错误解决标准流程and 错误resin4 resin chinese char path 404 err解决 1. #原因解析 1 2. #解决方式 2 3. 输出图片流... 2 ...

  9. CCCallFunc CCCallFuncN CCCallFuncND的区别和使用

    CCCallFunc CCCallFuncN CCCallFuncND都用来创建带有回调函数的动作,区别主要在于回调函数是否带有参数 CCCallFunc是执行对应的回调函数,其中回调函数不可带参数. ...

  10. CXCommon.h工具类

    #ifndef __XCOMMON_H__ #define __XCOMMON_H__ /******************************************************* ...