FutureTask详解
Posted truestoriesavici01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FutureTask详解相关的知识,希望对你有一定的参考价值。
FutureTask详解
简介
- FutureTask为Future的实现类.
- 用以获取任务执行结果(get)和取消任务(cancel).
- 若任务未完成,则获取任务结果时会被阻塞.
- 若任务执行完成后,任务不能被重启或取消.
- 可用作一个任务提交到线程中执行.
- 线程安全由CAS保证.
- FutureTask实现RunnableFuture接口,该接口继承了Runnable接口和Future接口.FutureTask可以被Thread直接执行,也可以作为Future用作Callable的计算结果.
用法
Callable接口
有返回值,可以返回子任务执行的结果.
Future接口
表示异步计算的结果,可以:
- 查询异步计算任务是否执行完成
- 获取异步计算的结果
- 中断异步任务的执行
接口定义
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
解释:
cancel()
: 取消子任务的执行.- 若子任务已执行结束/已被取消/不能取消,则方法执行失败,返回false.
- 若子任务没有开始执行,子任务被取消,不再被执行.
- 若子任务已开始执行,没有执行结束,则根据
mayInterruptIfRunning
判断:- 若为true,则段执行任务的线程,返回true.
- 若为false,则返回true,不中断执行任务的线程.
isCancelled()
: 判断任务是否被取消.- 若任务执行结束(正常结束,发生异常结束)前被取消,返回true.(即调用
cancel()
返回true) - 否则返回false.
- 若任务执行结束(正常结束,发生异常结束)前被取消,返回true.(即调用
idDone()
: 判断任务是否执行结束.(以下情况返回true,否则返回false)- 正常执行结束.
- 发生异常结束.
- 被取消.
get()
: 获取结果.- 若任务没有执行结束,则调用线程进入阻塞状态.
- 若任务已被取消,则抛出
CancellationException
异常. - 若执行过程中抛出异常,则抛出
ExecutionException
异常. - 若当前线程在阻塞时被中断,抛出
InterruptedException
异常.
get(long timeout, TimeUnit unit)
:设定超时限制的get()
,等待超时后,抛出TimeOutException
异常.
FutureTask
成员变量
state
: 用来表示当前任务的运行状态.- NEW(=0): 新任务/没有执行完的任务.
- COMPLETING(=1): 任务执行结束(正常结束,发生异常结束),但结果没有保存到
outcome
中. - NORMAL: 任务正常执行结束,结果保存到
outcome
中. - CANCELLED: 任务执行结束前被取消,不要求中断正在执行的线程.
- INTERRUPTING: 任务执行结束之前被取消,要求中断线程的执行.
- INTERRUPTED: 调用
cancel(true)
取消异步任务,会调用interrupt()
中断线程的执行.
callable
: 封装计算任务,获取计算结果.outcome
: 保存计算任务的返回结果/执行过程中抛出的异常.runner
: 指向当前运行的callable
任务的线程.waiters
: 任务没有结束,调用get()
方法的线程会被阻塞,进入阻塞队列排队等待.
状态转移:
- NEW-->COMPLETING-->NORMAL : 正常执行结束
- NEW-->COMPLETING-->EXCEPTIONAL : 执行过程中发生异常
- NEW-->CANCELLED : 被取消,调用
cancel(false)
- NEW-->INTERRUPTING-->INTERRUPTED : 被中断,调用
cancel(false)
核心方法
任务执行 run()
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 = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
流程:
- 如果任务不是新建的任务或者无法运行该任务,则直接返回,不作处理.
- 获取任务并检查任务是否是新建的,满足条件则试图执行任务.
- 若执行任务过程中出现异常任务未完成,则清空任务,并设置任务状态为EXCEPTIONAL.
- 检查任务是否完成,完成则设置状态为NORMAL.
- 最后检查任务是否被中断过.若被中断过,则响应中断.
获取任务的执行结果 get()
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s); // 若正常结束,则返回结果.否则抛出异常
}
流程:
- 获取任务状态.
- 若未完成,则等待完成后返回结果.
- 若已完成,则直接返回结果.
- 若被取消或执行过程中出现异常,则抛出异常.
取消任务 cancel(boolean mayInterruptIfRunning)
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try {
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally {
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
流程:
- 若任务已执行完成或者无法设置状态为中断或取消时,则直接返回.
- 设置为要求中断,则试图中断线程,并设置任务状态为INTERRUPETED.
- 唤醒等待队列的线程.
子线程返回结果的最后一步 finishCompletion()
private void finishCompletion() {
for (WaitNode q; (q = waiters) != null;) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null;
q = next;
}
break;
}
}
done();
callable = null;
}
解释: 在子线程返回结果时,试图唤醒等待队列中的所有阻塞线程.
对于设置阻塞等待时间的线程,若阻塞时间未到但任务已经返回结果,则无需继续等待,直接返回结果.
小结
FutureTask主要采用CAS来替代锁,实现多线程并发.
参考:
以上是关于FutureTask详解的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# JUC线程池: FutureTask详解
Java并发编程- FutureTask详解与池化思想的设计和实战二
Java并发编程- FutureTask详解与池化思想的设计和实战二