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用法及解析的更多相关文章

  1. C# yield return 用法与解析

    原文:C# yield return 用法与解析 C# yield return 用法与解析 本文参考自:http://www.jb51.net/article/54810.htm 当初没有认真理解 ...

  2. AFNetworking 使用总结 (用法+JSON解析)

    « AFNetworking 图片的本地缓存问题 Get application bundle seed ID in iOS » AFNetworking 使用总结 (用法+JSON解析)    Fr ...

  3. jquery.cookie用法详细解析,封装的操作cookie的库有jquery.cookie.js

    jquery.cookie用法详细解析 需要注意存入cookie前,对数据进行序列化, 得到后在反序列化: 熟练运用:JSON.stringify();和JSON.parse(): 通常分为如下几个步 ...

  4. List<T>集合的Sort自定义排序用法简单解析

    List<T>集合的Sort自定义排序用法简单解析: 如下:一系列无序数字,如果想要他们倒序排列,则使用如下代码: 那么如何理解这段代码呢? (x,y)表示相邻的两个对象,如果满足条件:x ...

  5. 完善_IO, _IOR, _IOW, _IOWR 宏的用法与解析

    _IO, _IOR, _IOW, _IOWR 宏的用法与解析  原文地址:http://www.eefocus.com/ayayayaya/blog/12-03/245777_20cdd.html 作 ...

  6. FutureTask 源码解析

    FutureTask 源码解析 版权声明:本文为本作者原创文章,转载请注明出处.感谢 码梦为生| 刘锟洋 的投稿 站在使用者的角度,future是一个经常在多线程环境下使用的Runnable,使用它的 ...

  7. latex用法疑难解析

    latex用法疑难解析 1.问题:如何生成ps(PostScript)文件? 回答: 方法有二 (1)用dvips这个工具,在WinEdt编辑器中专门有一个按钮: (2)如果使用windows系统的话 ...

  8. yield关键字用法与解析(C# 参考)

    yield 关键字向编译器指示它所在的方法是迭代器块. 编译器生成一个类来实现迭代器块中表示的行为. 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值. 这是一个返 ...

  9. sql server 计算属性,计算字段的用法与解析

    SQL学习之计算字段的用法与解析   一.计算字段 1.存储在数据库表中的数据一般不是应用程序所需要的格式.大多数情况下,数据表中的数据都需要进行二次处理.下面举几个例子. (1).我们需要一个字段同 ...

随机推荐

  1. [NOIP10.5模拟赛]1.a题解--离散化+异或线段树

    题目链接: 咕咕咕 https://www.luogu.org/problemnew/show/CF817F 闲扯 在Yali经历几天折磨后信心摧残,T1数据结构裸题考场上连暴力都TM没打满 分析 观 ...

  2. javaweb开发技术--监听器

    监听器定义:是指专门用于其他对象身上发生的事件或状态改变进行监听和相应的处理的对象,当被监视的对象发生变化时立即采取相应的行动. web监听器的定义:servlet规范中定义的一种特殊类.用于监听Se ...

  3. Redis和MemCache静态Map做缓存区别

    本地缓存和分布式缓存 本地缓存:使用自带的map或者guava实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着jvm的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不 ...

  4. Delphi 方法指令字

  5. PHP面试题--基础

    1.PHP语言的一大优势是跨平台,什么是跨平台?一.PHP基础: PHP的运行环境最优搭配为Apache+MySQL+PHP,此运行环境可以在不同操作系统(例如windows.Linux等)上配置,不 ...

  6. shell变量引用

    var="www.sina.com.cn" echo ${var#*.} #sina.com.cn 从前向后删 echo ${var##*.} #.cn 贪婪模式从前向后删 ech ...

  7. 洛谷P1462 通往奥格瑞玛的道路(SPFA+二分答案)

    题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...

  8. 牛客小白月赛19 E 「火」烈火燎原 (思维,树)

    牛客小白月赛19 E 「火」烈火燎原 (思维,树) 链接:https://ac.nowcoder.com/acm/contest/2272/E来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空 ...

  9. P2402 奶牛隐藏 二分+网络流

    floyd搞出两点间最短距离 二分判答案 // luogu-judger-enable-o2 #include<bits/stdc++.h> using namespace std; ty ...

  10. 引爆炸弹——DFS&&联通块

    题目 链接 在一个$n \times m$方格地图上,某些方格上放置着炸弹.手动引爆一个炸弹以后,炸弹会把炸弹所在的行和列上的所有炸弹引爆,被引爆的炸弹又能引爆其他炸弹,这样连锁下去. 现在为了引爆地 ...