1 基本概念

1.1 Callable与Future

Runnable封装一个异步运行的任务,可以把它想象成为一个没有参数和返回值的异步方法。Callable与Runnable类似,但是有返回值。Callable接口是一个参数化的类型,只有一个方法call。

public interface Callable<V> {
V call() throws Exception;
}

类型参数是返回值的类型。例如,

Callable<Integer>表示一个最终返回Integer对象的异步计算。

Future保存异步计算的结果。可以启动一个计算,将Future对象交给某个线程,然后忘掉它。Future对象的所有者在结果计算好之后就可以获得它。

Future接口具有下面的方法:

public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

第一个get方法的调用被阻塞,知道计算完成。如果在计算完成之前,第二个get方法的调用超时,抛出一个TimeoutException异常。如果运行该计算的线程被中断,两个方法都将抛出InterruptedException。如果计算已经完成,那么get方法立即返回。

如果计算还在进行,isDone方法返回false;如果完成了,则返回true。

可以用cancel方法取消该计算。如果计算还没有开始,它被取消且不再开始。如果计算处于运行之中,那么如果mayInterrupt参数为true,它就被中断。

1.2 FutureTask

FutureTask包装器是一种非常便利的机制,同时实现了Future和Runnable接口。

类图如下:

FutureTask的状态转换过程:

 * NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED

1.3 FutureTask的执行过程

创建一个futureTask对象task
提交task到调度器executor等待调度或者在另外一个线程中执行task 等待调度中... 如果此时currentThread调取执行结果task.get(),会有几种情况
if task 还没有被executor调度或正在执行中
阻塞当前线程,并加入到一个阻塞链表中waitNode
else if task被其它Thread取消,并取消成功 或task处于中断状态
throw exception
else if task执行完毕,返回执行结果,或执行存在异常,返回异常信息 如果此时有另外一个线程调用task.get() 执行过程同上

2 应用场景

1. Future用于异步获取执行结果或者取消任务。
2. 在高并发场景下确保任务只执行一次。

3 基本例子

Callable<Integer> myComputation = ...;
FutureTask<Integer> task = new FutureTask<Integer>(myComputation);
Thread t = new Thread(task);
t.start();
...
Integer result = task.get(); //获取结果

4 FutureTask源码分析

4.1 核心状态

 /**
* The run state of this task, initially NEW. The run state
* transitions to a terminal state only in methods set,
* setException, and cancel. During completion, state may take on
* transient values of COMPLETING (while outcome is being set) or
* INTERRUPTING (only while interrupting the runner to satisfy a
* cancel(true)). Transitions from these intermediate to final
* states use cheaper ordered/lazy writes because values are unique
* and cannot be further modified.
*
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;

4.2 创建FutureTask

public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
} public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}

4.3 获取执行结果

public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
} public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
}

4.4 执行方法

public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}

4.5 设置状态

protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
} protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}

5 高级示例

public class Memoizer<A, V> implements Computable<A, V> {
private final ConcurrentMap<A, Future<V>> cache = new ConcurrentMap<A, Future>>();
private final Computable<A, V> c; public Memoizer(Computable<A, V> c) {
this.c = c;
} public C computer(final A arg) throws InterruptedException {
while(true) {
Future<V> f = cache.get(arg);
if(f == null) {
Callable<V> eval = new Callable<V>() {
public V call() throws InterruptedException {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
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(e.getCause());
}
}
}
}

FutureTask详解的更多相关文章

  1. Callable,Future和FutureTask详解

    1.Callable和Runnable 看Callable接口: public interface Callable<V> { /** * Computes a result, or th ...

  2. Future、Callable 、FutureTask详解

    1.Future和Callable Future是一个接口表示异步计算的结果,它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果.Future提供了get().cancel().isC ...

  3. [转]FutureTask详解

     FutureTask类是Future 的一个实现,并实现了Runnable,所以可通过Excutor(线程池) 来执行,也可传递给Thread对象执行.如果在主线程中需要执行比较耗时的操作时,但又不 ...

  4. Java并发编程的艺术笔记(九)——FutureTask详解

    FutureTask是一种可以取消的异步的计算任务.它的计算是通过Callable实现的,多用于耗时的计算. 一.FutureTask的三种状态 二.get()和cancel()执行示意 三.使用 一 ...

  5. 最强Java并发编程详解:知识点梳理,BAT面试题等

    本文原创更多内容可以参考: Java 全栈知识体系.如需转载请说明原处. 知识体系系统性梳理 Java 并发之基础 A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解 ...

  6. (转)深入详解Java线程池——Executor框架

    转:https://yq.aliyun.com/articles/633782?utm_content=m_1000015330 在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定 ...

  7. JAVA线程池原理详解二

    Executor框架的两级调度模型 在HotSpot VM的模型中,JAVA线程被一对一映射为本地操作系统线程.JAVA线程启动时会创建一个本地操作系统线程,当JAVA线程终止时,对应的操作系统线程也 ...

  8. Java多线程编程中Future模式的详解

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  9. 详解Executor框架

    在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...

随机推荐

  1. python读取文件中的字典

    import ast def file_read():    with open('D:\\pytharm\\jichuyufa\\day2\\pro_cty_con.txt', 'r', encod ...

  2. 【Flutter】Flutter 一些常用库

    Flutter社区和资源传送门 新: 慕课网<Flutter入门与案例实战>   |   中文网<Flutter实战>电子书 字体图标生成 http://fluttericon ...

  3. yum lnmp

    1.关闭防火墙 [root@CentOS ~]# chkconfig iptables off   2.关闭selinux vi /etc/sysconfig/selinux //将SELINUX=e ...

  4. python入门-函数(二)

    1 函数传递参数 def greet_users(names): """向列表中的每个用户都发处问候""" for name in name ...

  5. 【Javascript Demo】遮罩层和百度地图弹出层简单实现

    其实想做的就是显示百度地图的弹出层,现在已经简单实现了.示例和代码如下,点击按钮可以看到效果: 1.示例:   2.代码: <!DOCTYPE html PUBLIC "-//W3C/ ...

  6. 基于OpenGL编写一个简易的2D渲染框架-02 搭建OpenGL环境

    由于没有使用GLFW库,接下来得费一番功夫. 阅读这篇文章前请看一下这个网页:https://learnopengl-cn.github.io/01%20Getting%20started/02%20 ...

  7. from __future__ import division

    导入python未来支持的语言特征division(精确除法),当我们没有在程序中导入该特征时,"/"操作符执行的是截断除法(Truncating Division),当我们导入精 ...

  8. mysql 列转行

    第一种方法:使用序列化表的方法实现列转行 第一种方法:使用UNION的方法实现列转行 第二种方法:使用序列化表的方法实现列转行

  9. poi转geohash

    import geohashimport sysfor line in sys.stdin: fields = line.strip().split('\t') hostid,POS_TIME,POS ...

  10. Mysql InnoDB 数据更新 锁表

    一.数据表结构 1 2 3 4 5 6 7 8 9 10 CREATE TABLE `jx_attach` (   `attach_id` int(11) NOT NULL AUTO_INCREMEN ...