1、在异步任务进程中,一种常见的场景是,主线程提交多个异步任务,然后希望有任务完成就处理结果,并且按任务完成顺序逐个处理,对于这种场景,Java 并发包提供了一个方便的方法,使用 CompletionService,这是一个接口,它的实现类是 ExecutorCompletionService。

2、与 ExecutorService 一样,CompletionService 也可以提交异步任务,它的不同是,它可以按任务完成顺序获取结果,其具体定义为:

1
2
3
4
5
6
7
public interface <> {
Future<V> submit(Callable<V> task);
Future<V> submit(Runnable task, V result);
Future<V> take() throws InterruptedException;
Future<V> poll();
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
}

submit 方法与 ExecutorService 是一样的,多了 take 和 poll 方法,它们都是获取下一个完成任务的结果,take() 会阻塞等待,poll() 会立即返回,如果没有已完成的任务,返回 null,带时间参数的 poll 方法会最多等待限定的时间。

2、CompletionService 的主要实现类是 ExecutorCompletionService,它依赖于一个 Executor 完成实际的任务提交,而自己主要负责结果的排队和处理。它的构造方法有两个:

1
2
public ExecutorCompletionService(Executor executor)
public ExecutorCompletionService(Executor executor, BlockingQueue<Future<V>> completionQueue)

至少需要一个 Executor 参数,可以提供一个 BlockingQueue 参数,用作完成任务的队列,没有提供的话,ExecutorCompletionService 内部会创建一个 LinkedBlockingQueue。

3、ExecutorCompletionService 是怎么让结果有序处理的呢?
因为它有一个额外的队列,每个任务完成之后,都会将代表结果的 Future 入队。在 FutureTask 中,任务完成后,不管是正常完成、异常结束、还是被取消,都会调用 finishCompletion 方法,而该方法会调用一个 done 方法 protected void done() { } 该方法的实现为空,但它是一个 protected 方法,子类可以重写该方法。ExecutorCompletionService 的内部类 QueueingFuture 中重写了该方法。

在 ExecutorCompletionService 中,提交的任务类型不是一般的 FutureTask,而是一个子类 QueueingFuture

大专栏  Java 线程总结(十四)>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}
----------------------------

private final BlockingQueue<Future<V>> completionQueue;

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;
}
---------------------------

而 ExecutorCompletionService 的 take/poll 方法就是从该队列获取结果:

1
2
3
public Future<V> take() throws InterruptedException {
return completionQueue.take();
}

4、AbstractExecutorService 的 invokeAny 的实现,就利用了 ExecutorCompletionService,它的基本思路是,提交任务后,通过 take 方法获取结果,获取到第一个有效结果后,取消所有其他任务。

5、CompletionService 它通过一个额外的结果队列,方便了对于多个异步任务结果的处理。

参考博客

Java编程的逻辑 - 方便的 CompletionService

Java 线程总结(十四)的更多相关文章

  1. “全栈2019”Java多线程第十四章:线程与堆栈详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  2. “全栈2019”Java多线程第二十四章:等待唤醒机制详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. Java进阶(三十四)Integer与int的种种比较你知道多少?

    Java进阶(三十四)Integer与int的种种比较你知道多少? 前言 如果面试官问Integer与int的区别:估计大多数人只会说到两点:Ingeter是int的包装类,注意是一个类:int的初值 ...

  4. 《Java程序设计》十四次作业

    <Java程序设计>十四次作业实验总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 3. 代码量统计 周次 总代码量 新增代码量 总文件数 新增 ...

  5. “全栈2019”Java异常第十四章:将异常输出到文本文件中

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  6. “全栈2019”Java第八十四章:接口中嵌套接口详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  7. “全栈2019”Java第七十四章:内部类与静态内部类相互嵌套

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. “全栈2019”Java第六十四章:接口与静态方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  9. “全栈2019”Java第五十四章:多态详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. Vue专题-路由系统

    一切分离都是为了更好的结合,本文详细介绍了前后端分离架构之后,前端如果实现路由控制,即Vue路由系统. Vue路由系统 VueRouter实现原理 VueRouter的实现原理是根据监控锚点值的改变, ...

  2. share团队冲刺9

    团队冲刺第九天 昨天:完善代码 今天:修改代码中的问题,提高兼容性 问题:无

  3. 2019 Python工程师平均薪资22K,又涨了11.9%!

    转行的同学最关心的就是Python的薪资情况了.今天我们就来具体看一下Python现在的薪资情况. 这是一张网友统计的Python工程师工资情况图表.详细说明了现在Python工程师在各个城市的薪资情 ...

  4. shell 命令综合实战

    此篇为运维人员(开发)经常使用的查看系统状态的相关命令,主要综合了awk,grep ,sed等文本处理命令,能够大大提高工作效率,在此做个简单分享,也便于自己以后查找,毕竟好记性不如烂笔头. 获取et ...

  5. 试验指标|试验单位|均方|随机模型|固定模型|字母标记法|LSR|q检验|LSD|重复值|弥补缺失数据|可加性|平方根转换|对数转换|反正弦转化

    第五章 方差分析 试验指标是什么? 就是统计的测量值,eg:身高体重 试验单位( experimental unit )是什么? 实验载体,比如一只小白鼠 均方是什么? 就是方差 随机模型的τ有何特点 ...

  6. Idea创建Spring项目

    环境 win7 + Idea2018 Classpath commons-logging-1.2 + spring-framework-4.1.6.RELEASE Step1 创建工程 File -& ...

  7. Tensorflow学习教程------下载图像识别模型inceptionV3

    # coding: utf-8 import tensorflow as tf import os import tarfile import requests #inception模型下载地址 in ...

  8. 小白学习之pytorch框架(4)-softmax回归(torch.gather()、torch.argmax()、torch.nn.CrossEntropyLoss())

    学习pytorch路程之动手学深度学习-3.4-3.7 置信度.置信区间参考:https://cloud.tencent.com/developer/news/452418 本人感觉还是挺好理解的 交 ...

  9. Python笔记_第一篇_面向过程_第一部分_8.画图工具(小海龟turtle)

    turtle 是一个简单的绘图工具. 提供一个小海龟,可以把它理解为一个机器人,只能听懂有限的命令,且绘图窗口的原点(0,0)在中间,默认海龟的方向是右侧海龟的命令包括三类:运动命令.笔画控制命令.其 ...

  10. linux 中的.so和.a文件

    Linux下的.so是基于Linux下的动态链接,其功能和作用类似与windows下.dll文件. 下面是关于.so的介绍: 一.引言 通常情况下,对函数库的链接是放在编译时期(compile tim ...