博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CompletionService 简介
阅读量:6427 次
发布时间:2019-06-23

本文共 2743 字,大约阅读时间需要 9 分钟。

hot3.png

        当向Executor提交批处理任务时,并且希望在它们完成后获得结果,如果用FutureTask,你可以循环获取task,并用future.get()去获取结果,但是如果这个task没有完成,你就得阻塞在这里,这个实效性不高,其实在很多场合,其实你拿第一个任务结果时,此时结果并没有生成并阻塞,其实在阻塞在第一个任务时,第二个task的任务已经早就完成了,显然这种情况用future task不合适的,效率也不高。

       自己维护list和CompletionService的区别:

  1. 从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。
  2. 而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。
    
  CompletionService采取的是BlockingQueue<Future<V>>无界队列来管理Future。则有一个线程执行完毕把返回结果放到BlockingQueue<Future<V>>里面。就可以通过completionServcie.take().get()取出结果。

         方法区别:

  • take 方获取并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则等待。<如果需要用到返回值建议用take>
  • poll 获取并移除表示下一个已完成任务的 Future,如果不存在这样的任务,则返回null。

以下是jdk关于CompletionService的简介:

  •    public interface CompletionService<V>
  • 将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务,并按照完成这些任务的顺序处理它们的结果。例如,CompletionService 可以用来管理异步 IO ,执行读操作的任务作为程序或系统的一部分提交,然后,当完成读操作时,会在程序的不同部分执行其他操作,执行操作的顺序可能与所请求的顺序不同。
  • 通常,CompletionService 依赖于一个单独的 Executor 来实际执行任务,在这种情况下,CompletionService 只管理一个内部完成队列。ExecutorCompletionService 类提供了此方法的一个实现。 
  • 内存一致性效果:线程中向 CompletionService 提交任务之前的操作 happen-before 该任务执行的操作,后者依次 happen-before 紧跟在从对应 take() 成功返回的操作。 

废话少说,直接看代码:

package com.lucky.concurrent;import java.util.Random;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;public class CompletionServiceDemo {	public static class Task implements Callable
{ private int i; Task(int i) { this.i = i; } @Override public Integer call() throws Exception { Thread.sleep(new Random().nextInt(5000)); System.out.println(Thread.currentThread().getName() + " " + i); return i; } } public void run() { ExecutorService pool = Executors.newFixedThreadPool(10); CompletionService
completionServcie = new ExecutorCompletionService
( pool); try { for (int i = 0; i < 10; i++) { completionServcie.submit(new CompletionServiceDemo.Task(i)); } for (int i = 0; i < 10; i++) { // take 方法等待下一个结果并返回 Future 对象。 // poll 不等待,有结果就返回一个 Future 对象,否则返回 null。 System.out.println(completionServcie.take().get()); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } finally { pool.shutdown(); } } public static void main(String[] args) { new CompletionServiceDemo().run(); }}
直接结果:

从结果中不难看出。只要有一个线程执行完毕后,主程序就立马获取结果。

转载于:https://my.oschina.net/jielucky/blog/158839

你可能感兴趣的文章
shell判断字符串相等脚本
查看>>
C++领域回调函数总结<一> ---- 常见使用
查看>>
如何在Mac OSX上用adb或DDMS连接小米2s做调试
查看>>
分公司网络建设----Juniper防火墙SRX240支持宽带拨号
查看>>
WTK在64位win7下安装的问题
查看>>
【函数】01、函数基础
查看>>
总结培训心得
查看>>
重载(overload)、覆盖(override)、隐藏(hide)的区别
查看>>
leetCode 189. Rotate Array 数组
查看>>
我的友情链接
查看>>
二惠竞爽,风雪庆贺佳途
查看>>
strspn()—字符查找函数
查看>>
NFS 服务器的部署
查看>>
人员登入5---实现登入
查看>>
解决chrome和IE下字号不一样现象
查看>>
Apache--SSI 服务器端包含
查看>>
加密和解密 tar
查看>>
我的友情链接
查看>>
[李景山php]每天TP5-20161216|thinkphp5-helper.php-1
查看>>
puppet案例解析
查看>>