并发编程 06—— CompletionService :Executor 和 BlockingQueue
Java并发编程实践 目录
并发编程 04—— 闭锁CountDownLatch 与 栅栏CyclicBarrier
并发编程 06—— CompletionService : Executor 和 BlockingQueue
并发编程 10—— 任务取消 之 关闭 ExecutorService
并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略
概述
第1部分 问题引入
《Java并发编程实践》一书6.3.5节CompletionService:Executor和BlockingQueue,有这样一段话:
"如果向Executor提交了一组计算任务,并且希望在计算完成后获得结果,那么可以保留与每个任务关联的Future,然后反复使用get方法,同时将参数timeout指定为0,从而通过轮询来判断任务是否完成。这种方法虽然可行,但却有些繁琐。幸运的是,还有一种更好的方法:完成服务CompletionService。"
这是什么意思呢?通过一个例子,分别使用繁琐的做法和CompletionService来完成,清晰的对比能让我们更好的理解上面的一段话和CompletionService这个API提供的初衷。
第2部分 实例
考虑这样的场景,有5个Callable任务分别返回5个整数,然后我们在main方法中按照各个任务完成的先后顺序,在控制台打印返回结果。
package com.concurrency.TaskExecution_6; import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit; /**
*
* @ClassName: ReturnAfterSleepCallable
* TODO
* @author Xingle
* @date 2014-9-16 上午9:20:34
*/
public class ReturnAfterSleepCallable implements Callable<Integer>{ private int sleepSeconds;
private int returnValue; public ReturnAfterSleepCallable(int sleepSeconds,int returnValue){
this.sleepSeconds = sleepSeconds;
this.returnValue = returnValue;
} @Override
public Integer call() throws Exception {
System.out.println("begin to execute "); TimeUnit.SECONDS.sleep(sleepSeconds);
return returnValue;
} }
1.繁琐的做法
通过一个List来保存每个任务返回的Future,然后轮询这些Future,直到每个Future都已完成。我们不希望出现因为排在前面的任务阻塞导致后面先完成的任务的结果没有及时获取的情况,所以在调用get方式时,需要将超时时间设置为0。
package com.concurrency.TaskExecution_6; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; /**
* 传统的繁琐做法
* @ClassName: TraditionalTest
* TODO
* @author Xingle
* @date 2014-9-16 上午10:06:21
*/
public class TraditionalTest { public static void main(String[] args){
int taskSize = 5;
ExecutorService executor = Executors.newFixedThreadPool(taskSize);
List<Future<Integer>> futureList = new ArrayList<Future<Integer>>(); for(int i= 1; i<=taskSize; i++){
int sleep = taskSize -1;
int value = i;
//向线程池提交任务
Future<Integer> future = executor.submit(new ReturnAfterSleepCallable(sleep, value));
//保留每个任务的Future
futureList.add(future);
}
// 轮询,获取完成任务的返回结果
while(taskSize > 0){
for (Future<Integer> future : futureList){
Integer result = null;
try {
result = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//任务已经完成
if(result!=null){
System.out.println("result = "+result);
//从future列表中删除已经完成的任务
futureList.remove(future);
taskSize --;
break;
}
}
}
// 所有任务已经完成,关闭线程池
System.out.println("all over ");
executor.shutdown();
} }
执行结果:
2.使用CompletionService
package com.concurrency.TaskExecution_6; 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; /**
* 使用CompletionService
* @ClassName: CompletionServiceTest
* TODO
* @author Xingle
* @date 2014-9-16 上午11:32:45
*/
public class CompletionServiceTest { public static void main(String[] args){
int taskSize = 5;
ExecutorService executor = Executors.newFixedThreadPool(taskSize);
// 构建完成服务
CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(executor); for (int i=1;i<= taskSize; i++){
// 睡眠时间
int sleep = taskSize - i;
// 返回结果
int value = i;
//向线程池提交任务
completionService.submit(new ReturnAfterSleepCallable(sleep, value));
try {
System.out.println("result:"+completionService.take().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
} System.out.println("all over. ");
executor.shutdown(); } }
执行结果:
3.CompletionService和ExecutorCompletionService的实现
JDK源码中CompletionService的javadoc说明如下:
/**
* A service that decouples the production of new asynchronous tasks
* from the consumption of the results of completed tasks. Producers
* <tt>submit</tt> tasks for execution. Consumers <tt>take</tt>
* completed tasks and process their results in the order they
* complete.
*/
public ExecutorCompletionService(Executor executor) {
if (executor == null)
throw new NullPointerException();
this.executor = executor;
this.aes = (executor instanceof AbstractExecutorService) ?
(AbstractExecutorService) executor : null;
this.completionQueue = new LinkedBlockingQueue<Future<V>>();
}
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
executor.execute(new QueueingFuture(f));
return f;
}
QueueingFuture是FutureTask的一个子类,通过改写FutureTask类的done方法,可以实现当任务完成时,将结果放入到BlockingQueue中。
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
FutureTask.done(),这个方法默认什么都不做,就是一个回调,当提交的线程池中的任务完成时,会被自动调用。这也就说时候,当任务完成的时候,会自动执行QueueingFuture.done()方法,将返回结果加入到阻塞队列中,加入的顺序就是任务完成的先后顺序。
并发编程 06—— CompletionService :Executor 和 BlockingQueue的更多相关文章
- Python并发编程06 /阻塞、异步调用/同步调用、异步回调函数、线程queue、事件event、协程
Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件event.协程 目录 Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件 ...
- Java 并发编程中的 Executor 框架与线程池
Java 5 开始引入 Conccurent 软件包,提供完备的并发能力,对线程池有了更好的支持.其中,Executor 框架是最值得称道的. Executor框架是指java 5中引入的一系列并发库 ...
- Java并发编程(08):Executor线程池框架
本文源码:GitHub·点这里 || GitEE·点这里 一.Executor框架简介 1.基础简介 Executor系统中,将线程任务提交和任务执行进行了解耦的设计,Executor有各种功能强大的 ...
- Java并发编程(06):Lock机制下API用法详解
本文源码:GitHub·点这里 || GitEE·点这里 一.Lock体系结构 1.基础接口简介 Lock加锁相关结构中涉及两个使用广泛的基础API:ReentrantLock类和Condition接 ...
- 并发编程-concurrent指南-阻塞队列BlockingQueue
阻塞队列BlockingQueue,java.util.concurrent下的BlockingQueue接口表示一个线程放入和提取实例的队列. 适用场景: BlockingQueue通常用于一个线程 ...
- 深入理解java:2.3.5. 并发编程concurrent包 之容器BlockingQueue(阻塞队列)
1. 什么是阻塞队列? 阻塞队列(BlockingQueue)是一个支持两个附加操作的队列. 这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空. 当队列满时,存储元素的线程会等待队列 ...
- day43 Pyhton 并发编程06
一.内容回顾 线程 锁 为什么有了GIL之后还需要锁 多个线程同时操作全局变量还需要锁 当出现'非原子性操作',例如+= -= *= /= l.append(l) 原子性操作 a += 1 a= a ...
- JUC 并发编程--06, 阻塞队列(7种), 阻塞等待 api的 代码验证
这些队列的 api ,就是添加队列,出队列,检测对首元素, 由于 add()--remove(), offer()--poll(),太简单这里不做验证, 只验证后二组api: 阻塞等待( put()- ...
- 并发编程 01—— ThreadLocal
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
随机推荐
- FIO是测试IOPS
FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, ...
- mysql安装配置问题(linux下)
1.安装后使用:mysql -u root -p 无法登录mysql 错误提示:ERROR 1045 (28000): Access denied for user 'root'@'localhost ...
- n皇后2种解题思路与代码-Java与C++实现
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了n皇后问题的解题思路,并分别用java和c++实现了过程,最后,对于算法改进 ...
- 读取input:file的路径并显示本地图片的方法
<!doctype html> <html> <head> <meta content="text/html; charset=UTF-8" ...
- C#实现执行多条SQl语句,实现数据库事务
C#实现执行多条SQl语句,实现数据库事务 在数据库中使用事务的好处,相信大家都有听过银行存款的交易作为事务的一个例子.事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的 ...
- java开发_读写txt文件操作
package com.mi.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStr ...
- Monkey之环境搭建完全版
图文版将在后期补充. 如果想要搭建好Monkey的测试环境,首先几个必要的步骤和环境不能少,分别是java相关环境.Android SDK环境,启动android虚拟机或连接真机.执行monkey测试 ...
- 关于加权的LIS问题
蒟蒻Zigzag正在准备联赛...... 这个算是这几天做的唯一一个值得写一写的题吧.首先LIS的N^2暴力dp应该都会写,就是F[i]=Max{F[j]}+1 那么加权的就吧后面的1换成数的权值就行 ...
- Centos6.7安装docker1.7.1
Docker当前发布的最新版本已经到了1.11,其官网上针对Centos的的安装需求如下: Docker requires a -bit installation regardless of your ...
- python:HTML + CSS 优先级 返回顶部
优先级 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...