浅谈Java Future接口
Java项目编程中,为了充分利用计算机CPU资源,一般开启多个线程来执行异步任务。但不管是继承Thread类还是实现Runnable接口,都无法获取任务执行的结果。JDK 5中引入了Callable和Future,通过它们执行异步任务可以获取执行结果。
FutureTask分析
JDK 5中获取任务执行的结果主要是通过FutureTask类实现的。FutureTask实现了RunnableFuture的接口,它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。一般结合线程池ExecutorService类使用,大致流程如下: 1. 调用线程将callable任务submit到线程池,返回Future对象 2. 任务被封装成FutureTask对象
<ignore_js_op>
- 执行线程调用FutureTask的run方法,run主要逻辑是执行Callable任务的call方法获取结果,并将结果赋值给全局变量outcome调用线程调用Future对象的get方法来获取任务执行的结果
上述步骤4中,如果任务没有执行完成,调用get方法时,调用线程将被阻塞直到任务完成。
假设这样的一个场景,向Executor批量提交了A、B两个任务,A任务耗时20ms,B任务耗时10ms,每个任务完成后就能根据结果继续做后面的事。在该场景中,B任务先完成A任务后完成,由于调用线程不知道哪个任务会先完成,只能按照任务的提交顺序调用get方法阻塞获取结果,最后要耗时20ms才会继续做A、B任务后面的事。
显然这种情况下用Future机制是不合适的,B任务先完成了却增加了额外的等待时间。这个问题的原因是Future没有提供好的方法去判断第一个完成的任务。当然你可以通过Future提供的isDone方法轮询的去判断第一个完成的任务,但会消耗无谓的CPU资源。
从上面的分析可以看到,单使用Future是不方便的,其主要原因有:一方面没有提供方法去判断第一个完成的任务;另一方面是 Future没有提供Callback机制,只能通过阻塞的get方法去获取结果。针对第一个问题,JAVA引入了CompletionService接口。
CompletionService分析
CompletionService整合了Executor和BlockingQueue的功能。CompletionService维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中。这样就确保执行时间较短的任务率先被存入队列中。与Future流程的不同主要是: 1. callable任务提交后,exexute方法执行的是封装成QueueingFuture的任务对象。QueueingFuture是FutureTask的子类,重写了done方法,在task执行完成之后将当前future添加到阻塞队列completionQueue
<ignore_js_op>
- 获取结果是通过CompletionService的take方法和poll方法,这两个方法都委托给了BlockingQueue,它会在结果不可用时阻塞
<ignore_js_op>
由实现可知,Future的回调行为是在ExecutorCompletionService中实现的,完成的任务会封装到一个队列中,供客户端询问时使用。Future本身是没有提供回调方法的。另外,使用CompletionService虽然能保证任务结果按照完成先后顺序排序,但仍存在调用阻塞的问题。Guava的ListenableFuture 和JDK8的CompletableFuture对Future进行了扩展,当计算结果完成后可以立即执行后续逻辑。
Future的扩展
Guava的ListenableFuture扩展了Future接口,是一个可以监听结果的Future。就是它可以监听异步执行的过程,执行完了,自动触发后续操作。常用的添加监听器的方法是Futures.addCallback方法,大致流程如下: 1. 每当对一个ListenableFuture增加回调时,都会向线程池提交监听任务callbackListener。该任务的run方法会通过getDone方法阻塞获取future的执行结果。代码片段见下:
<ignore_js_op>
- 获取结果后立即执行callback的onFailure方法或者onSuccess方法,不会阻塞调用
当然ListenableFuture的回调机制不是通用的,如果主任务异步执行子任务并且需等待返回结果,此时ListenableFuture的作用和Future几乎差不多,都是通过get方法阻塞获取结果。如果主任务不需要等待子任务的返回结果,但子任务一旦计算完成就做其他计算,此时使用ListenableFuture非常合适。
CompletableFuture是JDK1.8新增的的类,提供了非常强大的Future的扩展功能。可以对多个异步处理进行编排,实现更复杂的异步处理。它能够将回调放到与任务不同的线程中执行,也能将回调作为继续执行的同步函数,在与任务相同的线程中执行。大家可以参考CompletableFuture的API了解它提供的功能。
总结
在实际项目中,需要根据具体的业务场景选择合适的Future工具类来实现异步编程。如果项目中使用Java 8,推荐使用CompletableFuture类,它提供了更多的异步控制。如果使用之前版本,可以使用Guava等框架提供的Future工具类。
from: https://www.wengbi.com/thread_69744_1.html
浅谈Java Future接口的更多相关文章
- 浅谈Java中接口与抽象类的异同
浅谈Java中接口与抽象类的异同 抽象类和接口这两个概念困扰了我许久,在我看来,接口与抽象类真的十分相似.期间也曾找过许许多多的资料,参考了各路大神的见解,也只能是简简单单地在语法上懂得两者的区别.硬 ...
- 为什么这些java接口没有抽象方法?浅谈Java标记接口
在jdk的源码中,存在这样的一些接口,他们不包含任何的(抽象)方法,但是却广泛的存在. 这种接口我们称之为Mark Interface,也就是标记接口. 这些接口呢,我们不用来实现任何的方法,他们的作 ...
- 浅谈java中接口与抽象类之间的异同
刚学习java的时候,总觉得接口和抽象类很像,但又说不上具体有什么区别.今天静下来,翻翻书,查查资料,做个小结.首先举两个例子,看看interface和abstract class 在“外形”上有啥异 ...
- 浅谈Java接口(Interface)
浅谈Java接口 先不谈接口,不妨设想一个问题? 如果你写了个Animal类,有许多类继承了他,包括Hippo(河马), Dog, Wolf, Cat, Tiger这几个类.你把这几个类拿给别人用,但 ...
- 浅谈JAVA集合框架
浅谈JAVA集合框架 Java提供了数种持有对象的方式,包括语言内置的Array,还有就是utilities中提供的容器类(container classes),又称群集类(collection cl ...
- 浅谈Java中的深拷贝和浅拷贝(转载)
浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...
- !! 浅谈Java学习方法和后期面试技巧
浅谈Java学习方法和后期面试技巧 昨天查看3303回复33 部落用户大酋长 下面简单列举一下大家学习java的一个系统知识点的一些介绍 一.java基础部分:java基础的时候,有些知识点是非常重要 ...
- 浅谈Java中的深拷贝和浅拷贝
转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...
- 【转】浅谈Java中的hashcode方法(这个demo可以多看看)
浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...
随机推荐
- 【LOJ】#2080. 「JSOI2016」病毒感染
题解 那个限制表示一回头要治完前面的所有病人 我们处理一个g[i][j]表示治疗i到j的病人至少会死多少病人 \(g[i][j] = g[i + 1][j] + sum[i + 1,j] + min( ...
- 004.Zabbix3.x-Server服务端安装
一 环境基础 1.1 部署基础环境 部署Zabbix需要LAMP或LANP环境,数据库可以为MySQL或者MariaDB.硬件及存储条件按需配置. 1.2 常见依赖列表 Web前端需要支持的软件环境如 ...
- JAVA 图形开发之计算器设计(事件监听机制)
/*文章中用到的代码只是一部分,需要源码的可通过邮箱联系我 1978702969@qq.com*/ 前段时间刚帮同学用MFC写了个计算器,现在学到JAVA的图形开发,就试着水了一个计算器出来.(可以说 ...
- Django中的ORM关系映射查询方面
ORM:Object-Relation Mapping:对象-关系映射 在MVC框架中的Model模块中都包括ORM,对于开发人员主要带来了如下好处: 实现了数据模型与数据库的解耦,通过简单的配置就可 ...
- Python基础笔记(二)
1. List和Tuple List和Tuple是Python的内置的数据类型,区别在于可变和不可变,List用[]表示,Tuple用()表示,它们之间可以相互转换: # List to Tuple ...
- luogu P1401 城市
题目链接 luogu P1401 城市 题解 二分最小边权,dinic检验 代码 // luogu-judger-enable-o2 /* 二分最小边权,dinic检验 */ #include< ...
- BZOJ.3257.树的难题(树形DP)
题目链接 状态只与黑.白两点的颜色有关,于是用 \(f[x][i][j]\)表示当前以x为根节点,有\(i\)个黑点\(j\)个白点,使得x子树满足该条件的最小花费. 最后答案就是 \(min\{f[ ...
- NOI.AC NOIP模拟赛 第四场 补记
NOI.AC NOIP模拟赛 第四场 补记 子图 题目大意: 一张\(n(n\le5\times10^5)\)个点,\(m(m\le5\times10^5)\)条边的无向图.删去第\(i\)条边需要\ ...
- Linux shell 脚本小记2
.从文件读取 while read line do echo "line=$line" done < file.txt .将字符串转换为数组,并进行遍历 str=" ...
- 如何使用windows云服务器搭建IIs、windows服务
如何使用windows云服务器搭建IIs.windows服务,以下针对腾讯云服务器进行说明 1.购买云服务器之后,第1步需要设置的是,找到重装系统.重置密码等处. 2.设置安全组,设置完安全组之后才能 ...