from:  https://blog.csdn.net/linchunquan/article/details/22382487

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

1. FutureTask执行多任务计算的使用场景

利用FutureTask和ExecutorService,可以用多线程的方式提交计算任务,主线程继续执行其他任务,当主线程需要子线程的计算结果时,在异步获取子线程的执行结果。

2. FutureTask在高并发环境下确保任务只执行一次

在很多高并发的环境下,往往我们只需要某些任务只执行一次。这种使用情景FutureTask的特性恰能胜任。举一个例子,假设有一个带key的连接池,当key存在时,即直接返回key对应的对象;当key不存在时,则创建连接。对于这样的应用场景,通常采用的方法为使用一个Map对象来存储key和连接池对应的对应关系,典型的代码如下面所示:

    private Map<String, Connection> connectionPool = new HashMap<String, Connection>();
private ReentrantLock lock = new ReentrantLock(); public Connection getConnection(String key){
try{
lock.lock();
if(connectionPool.containsKey(key)){
return connectionPool.get(key);
}
else{
//创建 Connection
Connection conn = createConnection();
connectionPool.put(key, conn);
return conn;
}
}
finally{
lock.unlock();
}
} //创建Connection
private Connection createConnection(){
return null;
}

在上面的例子中,我们通过加锁确保高并发环境下的线程安全,也确保了connection只创建一次,然而确牺牲了性能。改用ConcurrentHash的情况下,几乎可以避免加锁的操作,性能大大提高,但是在高并发的情况下有可能出现Connection被创建多次的现象。这时最需要解决的问题就是当key不存在时,创建Connection的动作能放在connectionPool之后执行,这正是FutureTask发挥作用的时机,基于ConcurrentHashMap和FutureTask的改造代码如下:

    private ConcurrentHashMap<String,FutureTask<Connection>>connectionPool = new ConcurrentHashMap<String, FutureTask<Connection>>();

    public Connection getConnection(String key) throws Exception{
FutureTask<Connection>connectionTask=connectionPool.get(key);
if(connectionTask!=null){
return connectionTask.get();
}
else{
Callable<Connection> callable = new Callable<Connection>(){
@Override
public Connection call() throws Exception {
// TODO Auto-generated method stub
return createConnection();
}
};
FutureTask<Connection>newTask = new FutureTask<Connection>(callable);
connectionTask = connectionPool.putIfAbsent(key, newTask);
if(connectionTask==null){
connectionTask = newTask;
connectionTask.run();
}
return connectionTask.get();
}
} //创建Connection
private Connection createConnection(){
return null;
}

经过这样的改造,可以避免由于并发带来的多次创建连接及锁的出现。

FutureTask的方法执行示意图:

from: https://blog.csdn.net/javazejian/article/details/50896505

无论是Runnable接口的实现类还是Callable接口的实现类,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行,ThreadPoolExecutor或ScheduledThreadPoolExecutor都实现了ExcutorService接口,而因此Callable需要和Executor框架中的ExcutorService结合使用,我们先看看ExecutorService提供的方法:

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

第一个方法:submit提交一个实现Callable接口的任务,并且返回封装了异步计算结果的Future。
第二个方法:submit提交一个实现Runnable接口的任务,并且指定了在调用Future的get方法时返回的result对象。
第三个方法:submit提交一个实现Runnable接口的任务,并且返回封装了异步计算结果的Future。
因此我们只要创建好我们的线程对象(实现Callable接口或者Runnable接口),然后通过上面3个方法提交给线程池去执行即可。

我们根据FutureTask.run()的执行时机来分析其所处的3种状态:
(1)未启动,FutureTask.run()方法还没有被执行之前,FutureTask处于未启动状态,当创建一个FutureTask,而且没有执行FutureTask.run()方法前,这个FutureTask也处于未启动状态。
(2)已启动,FutureTask.run()被执行的过程中,FutureTask处于已启动状态。
(3)已完成,FutureTask.run()方法执行完正常结束,或者被取消或者抛出异常而结束,FutureTask都处于完成状态。

下面我们再来看看FutureTask的方法执行示意图(方法和Future接口基本是一样的,这里就不过多描述了)

分析:
(1)当FutureTask处于未启动或已启动状态时,如果此时我们执行FutureTask.get()方法将导致调用线程阻塞;当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或者抛出异常。
(2)当FutureTask处于未启动状态时,执行FutureTask.cancel()方法将导致此任务永远不会执行。
当FutureTask处于已启动状态时,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果任务取消成功,cancel(...)返回true;但如果执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时cancel(...)返回false。
当任务已经完成,执行cancel(...)方法将返回false。

FutureTask的用法及两种常用的使用场景 + FutureTask的方法执行示意图的更多相关文章

  1. FutureTask的用法以及两种常用的使用场景

    参考博客:https://blog.csdn.net/linchunquan/article/details/22382487 FutureTask可用于异步获取执行结果或取消执行任务的场景.通过传入 ...

  2. FutureTask的用法及两种常用的使用场景

    FutureTask可用于异步获取执行结果或取消执行任务的场景.通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过Fu ...

  3. js中replace的用法(两种常用举例,还有好多用法不一一列举)

    1.替换特定字符 <html><body> <script type="text/javascript"> var str="Visi ...

  4. Windows校验文件哈希hash的两种常用方式

    大家经常都到哪儿去下载软件和应用程序呢?有没想过下载回来的软件.应用程序或资源是否安全呢?在 Windows 10 和 Office 2016 发布当初,很多没权限的朋友都使用第三方网站去下载安装映像 ...

  5. Spring Cloud Config采用Git存储时两种常用的配置策略

    由于Spring Cloud Config默认采用了Git存储,相信很多团队在使用Spring Cloud的配置中心时也会采用这样的策略.即便大家都使用了Git存储,可能还有各种不同的配置方式,本文就 ...

  6. 两种常用的jquery事件加载的方法 的区别

    两种常用的jquery事件加载的方法   $(function(){});  window.onload=function(){}  第一个呢,是在DOM结构渲染完成以后调用的,这时候网页中一些资源还 ...

  7. iOS- 网络访问两种常用方式【GET & POST】实现的几个主要步骤

    1.前言 上次,在博客里谈谈了[GET & POST]的区别,这次准备主要是分享一下自己对[GET & POST]的理解和实现的主要步骤. 在这就不多废话了,直接进主题,有什么不足的欢 ...

  8. iOS- 网络请求的两种常用方式【GET & POST】的区别

    GET和POST 网络请求的两种常用方式的实现[GET & POST] –GET的语义是获取指定URL上的资源 –将数据按照variable=value的形式,添加到action所指向的URL ...

  9. css两种常用的不定宽高的水平垂直居中方法,记住它,不再为样式发愁

    css 几种常用的简单容易记住的水平垂直居中方法 前言 正文 第一种方法 第二种方法 结束语 前言 我们在设计网页时,会大量的运用到水平垂直居中,如果知道元素的宽高,那水平垂直居中是很简单的,无非是用 ...

随机推荐

  1. C#,ArcGIS Engine开发入门教程

    C#,ArcGIS Engine开发入门教程 转自:http://blog.csdn.net/yanleigis/article/details/2233674  目录(?)[+] 五实现 一 加载A ...

  2. Windows 环境下安装 Oracle JDK

    本页面中描述了如何在 Window 环境下安装 Oracle JDK. 我们使用的版本是 Window 10,我们需要安装的版本是 Oracle JDK 8u191. 检查当前版本 在进行新的 JDK ...

  3. 正睿 2019 省选附加赛 Day1 T1 考考试

    比较奇怪的一个枚举题. 注意到10=2*5,所以10^k的二进制表示一定恰好在末尾有k个0. 考虑从小到大去填这个十进制数. 填的时候记录一下当前的二进制表示. 每次尝试去填0或者10^k. 如果要填 ...

  4. Nastya Is Buying Lunch CodeForces - 1136D (排列)

    大意: 给定n排列, m个pair, 每个pair(u,v), 若u,v相邻, 且u在v左侧, 则可以交换u和v, 求a[n]最多向左移动多少 经过观察可以发现, 尽量先用右侧的人与a[n]交换, 这 ...

  5. POJ-1753 Flip Game (BFS+状态压缩)

    Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of i ...

  6. 在Windows下配置svn服务端钩子程序(部分)

    需求一,svn提交时必须填写log日志的需求,如何进行配置呢?请看下面. 需要在版本库目录下找到hooks文件夹,我的版本库是dxoffice,所以是这个目录,你要找自己的目录 然后进入,创建一个pr ...

  7. quartz---(1)

    Quartz Quartz是什么? 简单的一些例子 Quartz是什么 简单的认为Quartz是是一个定时器. 1.1. 下载 http://www.quartz-scheduler.org/down ...

  8. iOS UI-集合视图(UICollectionView)

    BowenCollectionViewCell.xib #import <UIKit/UIKit.h> @interface BowenCollectionViewCell : UICol ...

  9. css中 font常用的样式属性

    今天我总结一下文本常用的字体样式 1.font常用样式 1)字体类型 语法:font-family: +字体类型:    如: font-family:宋体; 2)字体大小 语法:font-size: ...

  10. 小程序数组型图片自适应效果的实现(交流QQ群:604788754)

    //本例代码如有问题,请加群,下载今日日期文件,测试.(如对本例有疑问,也可加群咨询群主) WXML: <view class="imgbox"> <block ...