FutureTask用法及解析
1 FutureTask概念
FutureTask一个可取消的异步计算,FutureTask 实现了Future的基本方法,提空 start cancel 操作,可以查询计算是否已经完成,并且可以获取计算的结果。结果只可以在计算完成之后获取,get方法会阻塞当计算没有完成的时候,一旦计算已经完成,那么计算就不能再次启动或是取消。
一个FutureTask 可以用来包装一个 Callable(一个有返回值的runnable) 或是一个runnable对象。因为FurtureTask实现了Runnable方法,所以一个 FutureTask可以提交(submit)给一个Excutor执行(excution).
2 FutureTask使用场景
FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。
请看下面代码:
public class Memoizer2<A, V> implements Computable<A, V> {
private final Map<A, V> cache = new ConcurrentHashMap<A, V>();
private final Computable<A, V> c;
public Memoizer2(Computable<A, V> c) {
this.c = c;
}
public V compute(A arg) throws InterruptedException {
V result = cache.get(arg);
if (result == null) {
/*
* 如果a线程进来,判断为空,开始compute,因为compute的时间比较长,而且put操作是在compute后面
* 所以其它线程不能及时得得到信息,所以这时b、c线程因为result为空而走进来(注意,abc三线程的arg是
* 一样的),于是乎b、c线程也执行compute方法,这样就会造成大量的线程执行重复的操作而导致效率极低
*/
result = c.compute(arg);
cache.put(arg, result);
}
return result;
}
}
针对上面的情况,我们可能会想,如果我们并不需要一定等到运算结果出来之后执行put,因为此时肯定有很多线程都因为result为null而执行重复的compute,所以我们想先快速定义一个对象并put,以该对象是否为null决定当前的arg是否运算过,这样就可以减少线程执行重复运算的概率,于是FutureTask类为此而来!
public class Memoizer<A, V> implements Computable<A, V> {
private final ConcurrentMap<A, Future<V>> cache = new ConcurrentHashMap<A, Future<V>>();
private final Computable<A, V> c;
public Memoizer(Computable<A, V> c) {
this.c = c;
}
public V compute(final A arg) throws InterruptedException {
while (true) {
Future<V> f = cache.get(arg);
if (f == null) {
/*
* 我们摒弃了之前通过判断运算后的值是否为空来决定是否要执行运算,而是判断future是否为null
* 为何?我们在判断f为null后到put操作之间,执行的动作仅仅只是new了俩对象,new俩对象的时间
* 肯定比执行compute短。
* 过程:a线程进来,判断f为null,new了callable和FutureTask,这时a线程立马将future加进map
* , 因为这段代码的速度很快,以至于b、c线程判断f不为null,直接执行future.get(),但是此时future
* 不一定运算完,所以b、c得等一会,知道a运算完后获取结果,这样我们的b、c线程就不用花时间去
* 执行重复的操作了,直接使用a线程的结果即可!!
*/
Callable<V> eval = new Callable<V>() {
public V call() throws InterruptedException {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
/*
* 注意,这里我们执行的不是普通的put操作,而是"没有则添加"的复合操作,不过这个方法已经提供了原子性
* 这样我们的程序就更安全了!!
*/
f = cache.putIfAbsent(arg, ft);
if (f == null) {
f = ft;
ft.run();
}
}
try {
return f.get();
} catch (CancellationException e) {
cache.remove(arg, f);
} catch (ExecutionException e) {
throw LaunderThrowable.launderThrowable(e.getCause());
}
}
}
}
总结:
(1)FutureTask是类似于Runnable的一种存在,可以接受Callable这种带返回结果的接口作构造参数
(2)FutureTask可以脱离主线程而单独开线程去执行其他运算操作
(3)一个FutureTask不论被多少个线程执行run,都只会执行一次,执行一次后就保持在“运算完成”的状态而不会回滚
(4)FutureTask可以保证:从运算线程返回的结果,可以安全的抵达调用运算线程的线程,中间不会出现线程安全问题
FutureTask用法及解析的更多相关文章
- C# yield return 用法与解析
原文:C# yield return 用法与解析 C# yield return 用法与解析 本文参考自:http://www.jb51.net/article/54810.htm 当初没有认真理解 ...
- AFNetworking 使用总结 (用法+JSON解析)
« AFNetworking 图片的本地缓存问题 Get application bundle seed ID in iOS » AFNetworking 使用总结 (用法+JSON解析) Fr ...
- jquery.cookie用法详细解析,封装的操作cookie的库有jquery.cookie.js
jquery.cookie用法详细解析 需要注意存入cookie前,对数据进行序列化, 得到后在反序列化: 熟练运用:JSON.stringify();和JSON.parse(): 通常分为如下几个步 ...
- List<T>集合的Sort自定义排序用法简单解析
List<T>集合的Sort自定义排序用法简单解析: 如下:一系列无序数字,如果想要他们倒序排列,则使用如下代码: 那么如何理解这段代码呢? (x,y)表示相邻的两个对象,如果满足条件:x ...
- 完善_IO, _IOR, _IOW, _IOWR 宏的用法与解析
_IO, _IOR, _IOW, _IOWR 宏的用法与解析 原文地址:http://www.eefocus.com/ayayayaya/blog/12-03/245777_20cdd.html 作 ...
- FutureTask 源码解析
FutureTask 源码解析 版权声明:本文为本作者原创文章,转载请注明出处.感谢 码梦为生| 刘锟洋 的投稿 站在使用者的角度,future是一个经常在多线程环境下使用的Runnable,使用它的 ...
- latex用法疑难解析
latex用法疑难解析 1.问题:如何生成ps(PostScript)文件? 回答: 方法有二 (1)用dvips这个工具,在WinEdt编辑器中专门有一个按钮: (2)如果使用windows系统的话 ...
- yield关键字用法与解析(C# 参考)
yield 关键字向编译器指示它所在的方法是迭代器块. 编译器生成一个类来实现迭代器块中表示的行为. 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值. 这是一个返 ...
- sql server 计算属性,计算字段的用法与解析
SQL学习之计算字段的用法与解析 一.计算字段 1.存储在数据库表中的数据一般不是应用程序所需要的格式.大多数情况下,数据表中的数据都需要进行二次处理.下面举几个例子. (1).我们需要一个字段同 ...
随机推荐
- linux文件目录详细介绍
linux文件目录 目录 /bin 存放二进制可执行文件(ls,cat,mkdir等),常用命令一般都在这里 /etc 存放系统管理和配置文件 /home 存放所有用户文件的根目录,是用户主目录的基点 ...
- 垃圾分类常见APP
垃圾分类指南app 上海就要实行垃圾分类了,垃圾分类指南app你需要吗,这里有相关的各种垃圾分类的介绍与上海垃圾分类投放指南,这里是垃圾分类指南手机入口能够让你更好的去完成垃圾分类呢.垃圾分类指 .. ...
- 1 java 笔记
第一java的版本: J2ME主要用于移动设备和信息家电 J2SE整个Java技术的核心 J2EE java技术应用最广泛的部分,主要应用与企业的开发 第二:基于java语言的开源框架 struts ...
- go module 设置
国内无法获取被墙的go module,解决方法,设置环境变量 GO111MODULE=on goproxy=https://goproxy.io
- sys和system用户的权限区别
http://blog.sina.com.cn/s/blog_869b0f460100uckp.html Oracle sys和system用户.sysdba 和sysoper系统权限.sysdba和 ...
- Mysql 指定字段数据排序 以及django的实现
业务场景: mysql 查询 select * from dormitory_applysettleorder order by FIELD(status,40) desc django 实现: or ...
- linux基础3-磁盘和文件系统相关
一 dumpe2fs : 在Linux使用过程中,我们如果要了解文件系统的配置情况,可以使用dumpe2fs查看ext2/ext3/ext4格式的文件系统信息. 命令格式: dumpe2fs [选项] ...
- NORDIC 错误文件
ble_err.h sdk_errors.h nrf_error.h app_error.h
- Hadoop_33_Hadoop HA的搭建
Hadoop HA的搭建,可参考链接:https://blog.csdn.net/mrbcy/article/details/64939623 说明: 1.在hadoop2.0中通常由两个Nam ...
- 2. An Array of Sequences
1. Overview of Built-In Sequences Container sequences: list, tuple, and collections.deque can hold i ...