Java并发之CompletionService详解
CompletionService是什么?
它是JUC包中的一个接口类,默认实现类只有一个ExecutorCompletionService。
CompletionService干什么的?
它将异步任务的生成和执行结果的处理进行了解耦,用来执行Callable的任务(实际也是通过Executor线程池执行的,只是它又加了一层封装),我们只需要调用它的take(阻塞)/poll(非阻塞)方法便可以获取到执行完的任务结果,最先获取到的必定是先执行完的异步任务结果。
主要应用场景:同时执行多个Callable任务,并且需对任务的返回结果进行处理。若想优先处理先执行完的任务结果,使用它尤其方便。
ExecutorCompletionService 源码解析
有三个成员变量,关键的是下面标注的变量1、变量2:
1 public class ExecutorCompletionService<V> implements CompletionService<V> {
2 private final Executor executor; // 变量1: 线程池
3 private final AbstractExecutorService aes;
4 private final BlockingQueue<Future<V>> completionQueue; // 变量2: 阻塞队列
两个构造器,如下,用于初始化上面的三个成员变量,可以看到Executor线程池是必传的:
1 public ExecutorCompletionService(Executor executor) {
2 if (executor == null)
3 throw new NullPointerException();
4 this.executor = executor;
5 this.aes = (executor instanceof AbstractExecutorService) ?
6 (AbstractExecutorService) executor : null;
7 this.completionQueue = new LinkedBlockingQueue<Future<V>>();
8 }
1 public ExecutorCompletionService(Executor executor,
2 BlockingQueue<Future<V>> completionQueue) {
3 if (executor == null || completionQueue == null)
4 throw new NullPointerException();
5 this.executor = executor;
6 this.aes = (executor instanceof AbstractExecutorService) ?
7 (AbstractExecutorService) executor : null;
8 this.completionQueue = completionQueue;
9 }
核心方法submit,把task封装成一个QueueingFuture,作为执行任务交给线程池执行:
1 public Future<V> submit(Callable<V> task) {
2 if (task == null) throw new NullPointerException();
3 RunnableFuture<V> f = newTaskFor(task);
4 executor.execute(new QueueingFuture(f));
5 return f;
6 }
下面再来看一下QueueingFuture对象,也是一个核心对象,如下所示。QueueingFuture是ExecutorCompletionService的私有内部类,它重写了FutureTask的done()方法。当任务执行完成set值的时候,会调用done方法,在done方法中将task存入阻塞队列。先执行完的任务就会先放入阻塞队列,所以我们从队列中取结果的时候,必定是先取到先执行完的任务。
1 private class QueueingFuture extends FutureTask<Void> {
2 QueueingFuture(RunnableFuture<V> task) {
3 super(task, null);
4 this.task = task;
5 }
6 protected void done() { completionQueue.add(task); }
7 private final Future<V> task;
8 }
总结一下,ExecutorCompletionService是通过QueueingFuture的done方法和阻塞队列实现的按照异步任务返回顺序来返回结果。
ExecutorCompletionService和ExecutorService的使用demo示例
Callable类:
1 class CsCallable implements Callable<String> {
2 private String name;
3 private long milli;
4
5 public CsCallable(String name, long milli) {
6 this.name = name;
7 this.milli = milli;
8 }
9
10 @Override
11 public String call() throws Exception {
12 System.out.println("name:" + name);
13 Thread.sleep(milli);
14 return name + " after " + milli + "ms call back.";
15 }
16 }
ExecutorCompletionService的demo:
1 public class CompletionServiceDemo {
2 public static void main(String[] args) throws Exception {
3 CompletionService completionService = new ExecutorCompletionService(Executors.newFixedThreadPool(4));
4 completionService.submit(new CsCallable("xxx", 5000));
5 completionService.submit(new CsCallable("www", 2000));
6 completionService.submit(new CsCallable("zzz", 14000));
7 completionService.submit(new CsCallable("yyy", 9000));
8 for (int i = 0; i < 4; i++) {
9 System.out.println(completionService.take().get());
10 }
11 System.out.println("----- main over -----");
12 }
13 }
执行结果如下,可以看到早完成的任务结果能先获取到:
ExecutorService的demo:
1 public class ExecutorServiceDemo {
2 public static void main(String[] args) throws Exception {
3 ExecutorService executorService = Executors.newFixedThreadPool(4);
4 List<Future<String>> list = new ArrayList<>();
5 list.add(executorService.submit(new CsCallable("xxx", 5000)));
6 list.add(executorService.submit(new CsCallable("www", 2000)));
7 list.add(executorService.submit(new CsCallable("zzz", 14000)));
8 list.add(executorService.submit(new CsCallable("yyy", 9000)));
9 for (Future<String> future : list) {
10 System.out.println(future.get());
11 }
12 System.out.println("----- main over -----");
13 }
14 }
执行结果如下,只能按照指定的顺序处理返回结果,无法先处理早完成的任务:
Java并发之CompletionService详解的更多相关文章
- Java并发之AQS详解
一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)! 类如其名,抽象的队列式的同步器,AQ ...
- Java并发之AQS详解(转)
一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronized(AQS)! 类如其名,抽象的队列式的同步器,AQ ...
- Java并发之ReentrantLock详解
一.入题 ReentrantLock是Java并发包中互斥锁,它有公平锁和非公平锁两种实现方式,以lock()为例,其使用方式为: ReentrantLock takeLock = new Reent ...
- java并发之CAS详解
前言 在高并发的应用当中,最关键的问题就是对共享变量的安全访问,通常我们都是通过加锁的方式,比如说synchronized.Lock来保证原子性,或者在某些应用当中,用voliate来保证变量的可见性 ...
- java并发之synchronized详解
前言 多个线程访问同一个类的synchronized方法时, 都是串行执行的 ! 就算有多个cpu也不例外 ! synchronized方法使用了类java的内置锁, 即锁住的是方法所属对象本身. 同 ...
- Android开发之InstanceState详解
Android开发之InstanceState详解 本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...
- Android开发之InstanceState详解(转)---利用其保存Activity状态
Android开发之InstanceState详解 本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...
- Android开发之MdiaPlayer详解
Android开发之MdiaPlayer详解 MediaPlayer类可用于控制音频/视频文件或流的播放,我曾在<Android开发之基于Service的音乐播放器>一文中介绍过它的使用. ...
- Java 8 Stream API详解--转
原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...
随机推荐
- void(*p)()和void*p()区别
void (*p)()是一个指向函数的指针,表示是一个指向函数入口的指地变量,该函数的返回类型是void类型.它的用法可参看下例: 例如:有一返加void值的函数swap,(swap用来交换两个数) ...
- centos 7.6安装WeADMIN ITOSS步骤
0.升级系统并安装必要的软件 yum -y update yum -y install wget unzip nmap 1.下载JDK jdk下载地址:http://www.oracle.com/te ...
- Flink-v1.12官方网站翻译-P021-State & Fault Tolerance-overview
状态和容错 在本节中,您将了解Flink为编写有状态程序提供的API.请看一下Stateful Stream Processing来了解有状态流处理背后的概念. 下一步去哪里? Working wit ...
- netty写Echo Server & Client完整步骤教程(图文)
1.创建Maven工程 1.1 父节点的pom.xml代码(root pom文件) 1 <?xml version="1.0" encoding="UTF-8&qu ...
- 一文弄懂-Netty核心功能及线程模型
目录 一. Netty是什么? 二. Netty 的使用场景 三. Netty通讯示例 1. Netty的maven依赖 2. 服务端代码 3. 客户端代码 四. Netty线程模型 五. Netty ...
- Educational Codeforces Round 89 (Rated for Div. 2) B. Shuffle(数学/双指针)
题目链接:https://codeforces.com/contest/1366/problem/B 题意 大小为 $n$ 的数组 $a$,除了 $a_x = 1$,其余 $a_i = 0$,依次给出 ...
- hdu5637 Transform (bfs+预处理)
Problem Description A list of n integers are given. For an integer x you can do the following operat ...
- 【poj 1182】食物链(图论--带权并查集)
题意:有3种动物A.B.C,形成一个"A吃B, B吃C,C吃A "的食物链.有一个人对N只这3类的动物有M种说法:第一种说法是"1 X Y",表示X和Y是同类. ...
- 【noi 2.6_9267】核电站(DP)
题意:n个数中不能同时选连续m个或以上,问方案数. 解法:f[i][j]表示从前i个中选,到第i个已经连续选了j个.j!=0时, =f[i-1][j-1] ; j=0时, =f[i-1][0~m-1 ...
- Codeforces Round #547 (Div. 3) C. Polycarp Restores Permutation (数学)
题意:有一长度为\(n\)的序列\(p\),现在给你\(q_i=p_{i+1}-q_i \ (1\le i\le n)\),问你是否能还原出原序列,如果能救输出原序列,否则输出\(-1\). 题解:由 ...