JDK文档描述:

public interface CompletionService<V>

将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务,并按照完成这些任务的顺序处理它们的结果。例如,CompletionService 可以用来管理异步 IO ,执行读操作的任务作为程序或系统的一部分提交,然后,当完成读操作时,会在程序的不同部分执行其他操作,执行操作的顺序可能与所请求的顺序不同。 

通常,CompletionService 依赖于一个单独的 Executor 来实际执行任务,在这种情况下,CompletionService 只管理一个内部完成队列。ExecutorCompletionService 类提供了此方法的一个实现。 

内存一致性效果:线程中向 CompletionService 提交任务之前的操作 happen-before 该任务执行的操作,后者依次 happen-before 紧跟在从对应 take() 成功返回的操作
所有已知实现类:
ExecutorCompletionService

子类的JDK描述:

public class ExecutorCompletionService<V>extends Objectimplements CompletionService<V>
使用提供的 Executor 来执行任务的 CompletionService。此类将安排那些完成时提交的任务,把它们放置在可使用 take 访问的队列上。该类非常轻便,适合于在执行几组任务时临时使用。

所有的方法:

方法摘要
 Future<V> poll()
          获取并移除表示下一个已完成任务的 Future,如果不存在这样的任务,则返回 null
 Future<V> poll(long timeout,
TimeUnit unit)


          获取并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则将等待指定的时间(如果有必要)。
 Future<V> submit(Callable<V> task)

          提交要执行的值返回任务,并返回表示挂起的任务结果的 Future。
 Future<V> submit(Runnable task, V result)

          提交要执行的 Runnable 任务,并返回一个表示任务完成的 Future,可以提取或轮询此任务。
 Future<V> take()

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

JDK自带的例子:

假定您有针对某个问题的一组求解程序,每个求解程序都能返回某种类型的 Result 值,并且您想同时运行它们,使用方法 use(Result r) 处理返回非 null 值的每个求解程序的返回结果。可以这样编写程序

void solve(Executor e, Collection<Callable<Result>> solvers)
throws InterruptedException, ExecutionException {
CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
for (Callable<Result> s : solvers)
ecs.submit(s);
int n = solvers.size();
for (int i = 0; i < n; ++i) {
Result r = ecs.take().get();
if (r != null)
use(r);
}
}

假定您想使用任务集中的第一个非 null 结果,而忽略任何遇到异常的任务,并且在第一个任务就绪时取消其他所有任务:

void solve(Executor e, Collection<Callable<Result>> solvers)
throws InterruptedException {
CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
int n = solvers.size();
List<Future<Result>> futures = new ArrayList<Future<Result>>(n);
Result result = null;
try {
for (Callable<Result> s : solvers)
futures.add(ecs.submit(s));
for (int i = 0; i < n; ++i) {
try {
Result r = ecs.take().get();
if (r != null) {
result = r;
break;
}
} catch(ExecutionException ignore) {}
}
}
finally {
for (Future<Result> f : futures)
f.cancel(true);
} if (result != null)
use(result);
}

自己写的例子:(谁先得到结果我就先取到谁的结果)

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;
import java.util.concurrent.Future; public class ThreadPool2 {
public static void main(String[] args) {
test2();
} private static void test2(){
ExecutorService es = Executors.newFixedThreadPool(5);
CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(es);
for(int i=1 ; i<=5; i++){
final int task = i;
cs.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
try {
Thread.sleep(new Random().nextInt(5000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Callable 任务【" + task + "】运行完成");
return new Random().nextInt(100);
}
});
}
System.out.println("我是取结果前的代码");
//异步取结果
for(int i=0; i<5; i++){
try {
System.out.println(cs.take().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.println("我是取结果后的代码");
es.shutdown();
}
}

运行的结果:

我是取结果前的代码
Callable 任务【3】运行完成
25
Callable 任务【1】运行完成
16
Callable 任务【4】运行完成
38
Callable 任务【5】运行完成
17
Callable 任务【2】运行完成
4
我是取结果后的代码

11、java5线程池之异步任务CompletionService的更多相关文章

  1. spring boot / cloud (四) 自定义线程池以及异步处理@Async

    spring boot / cloud (四) 自定义线程池以及异步处理@Async 前言 什么是线程池? 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线 ...

  2. spring boot自定义线程池以及异步处理

    spring boot自定义线程池以及异步处理@Async:什么是线程池?线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使 ...

  3. 基于C++11实现线程池的工作原理

    目录 基于C++11实现线程池的工作原理. 简介 线程池的组成 1.线程池管理器 2.工作线程 3.任务接口, 4.任务队列 线程池工作的四种情况. 1.主程序当前没有任务要执行,线程池中的任务队列为 ...

  4. Python Django 协程报错,进程池、线程池与异步调用、回调机制

    一.问题描述 在Django视图函数中,导入 gevent 模块 import gevent from gevent import monkey; monkey.patch_all() from ge ...

  5. 基于C++11的线程池实现

    1.线程池 1.1 线程池是什么? 一种线程管理方式. 1.2 为什么用线程池? 线程的创建和销毁都需要消耗系统开销,当线程数量过多,系统开销过大,就会影响缓存局部性和整体性能.而线程池能够在充分利用 ...

  6. 11 java 线程池 使用实例

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

  7. 基于C++11的线程池,简洁且可以带任意多的参数

    咳咳.C++11 加入了线程库,从此告别了标准库不支持并发的历史.然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程池.信号量等.线程池(thread pool) ...

  8. SpringBoot自定义线程池处理异步任务

    @Async异步调用 就不解释什么是异步调用了,Spring Boot中进行异步调用很简单 1.通过使用@Async注解就能简单的将原来的同步函数变为异步函数 package com.winner.s ...

  9. 8、java5线程池之动态缓存线程池newCachedThreadPool

    JDK文档描述 创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们.对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能.调用 execute 将重用以前构造的线程 ...

随机推荐

  1. Java正则表达式教程及示例

    本文由 ImportNew - ImportNew读者 翻译自 journaldev.欢迎加入翻译小组.转载请见文末要求. [感谢 @CuGBabyBeaR  的热心翻译.如果其他朋友也有不错的原创或 ...

  2. linux(ubuntu) 开发环境配置

    1,首先安装jdk,这是必然的. 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260 ...

  3. go语言之进阶篇方法表达式

    1.方法表达式 示例: package main import "fmt" type Person struct { name string //名字 sex byte //性别, ...

  4. VS2010新建Web网站与新建Web应用程序的区别 (转)

    在Visual Studio 2010中,除了可以使用“创建Web应用程序”的方式来构建自己的Web项目之外,还可以通过创建“Web网站”的方式来构建Web项其中,Web网站的创建方法:打开Visua ...

  5. RxJava RxLifecycle 生命周期 内存泄漏 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. Safari不兼容Javascript中的Date问题

    在IOS5以上版本(不包含IOS5)中的Safari浏览器能正确解释出Javascript中的 new Date('2013-10-21') 的日期对象,但是在IOS5版本里面的Safari解释new ...

  7. Hadoop2.2.0安装配置手册!完全分布式Hadoop集群搭建过程~(心血之作啊~~)

    http://blog.csdn.net/licongcong_0224/article/details/12972889 历时一周多,终于搭建好最新版本hadoop2.2集群,期间遇到各种问题,作为 ...

  8. 利用OSG实现模拟飞机尾迹-粒子系统

    利用OSG实现模拟飞机尾迹-粒子系统 粒子系统简介:         粒子系统是用于不规则模糊物体建模及图像生成的一种方法.         粒子系统是一种过程模型,即利用各种计算过程生成模型各个体素 ...

  9. Oracle中对数字加汉字的排序(完好)

    之前写过一篇 Oracle中对数字加汉字的排序以及REGEXP_SUBSTR介绍 后来在开发的过程中又遇到相似问题.数据不一样了,按之前的使用方法是不适用的. 之前的是数字在前汉字在后,最基本的差别是 ...

  10. LINUX 查找tomcat日志关键词

    #查询catalina.out日志文件中的关键词为2016-04-13 11:26:00的日志信息 grep -C 10 '2016-04-13 11:26:00' catalina.out |mor ...