What‘s the FutureTask
1.how do you think of async or sync
- Before the talking about future, we should to know what's the async and sync, and their are how to work on multiThread。
1. sync: sequential way of working. on the working, task or method on single thread must execute / visit sequentially.
2. async: on the contrary of the sync.
- 简而言之:
- 同步的思想是能够被大多数人接受的。在日常生活中,同步的方式就比如,A要炒鸡蛋西红柿。那么A首先需要准备打鸡蛋,接下来需要准备西红柿,有了鸡蛋和西红柿,A才能下锅炒菜。那么同步即需要等待上一事件的执行完毕,才可以执行当下的任务。
- 异步,这种不局限于同步思路的处理方式,主线程会将任务交给其他线程执行,在另一线程执行完毕后会通过回调/不回调来通知/不通知提交异步任务主线程/其他线程获取到线程的执行结果,异步的思路在于利用多线程的资源,同时不去阻塞主线程/当前线程的执行去执行计算/处理。
- 异步处理会消耗线程资源,并不是所有的任务都适合使用异步去处理,在项目中需要去评估哪些task需要被异步执行。
2. Future/FutureTask
- Future 的思想我们可以理解为快递单号,那么FutureTask就类似于快递公司。当你需要寄快递的时候,你的包裹即为目前的task,那么在此同时快递公司会给你一个快递单号,来记录是这次这个task的。正常此时这个FutureTask就会执行内部的run()进行运输包裹. 之后你也可以通过打电话给快递公司来cancel()取消你的任务,或者是通过isDone()来查看快递是否被寄到了。当然,如果你此时想要拆快递,那么就必须等待快递被送到,所以你就会一直get()查询阻塞等待快递公司通知你,快递是否被送到。当然,你的其他朋友也知道这个快递单号的时候,他也可以通过去get()去查找这个快递是否寄到目的地(Task的只是一个结果,不要理解为任务本身) 贴图:
- FutureTask的状态转移图
- FutureTask api
3. code
- Future解析
1. state Task任务状态:
private volatile int state;
private static final int NEW = 0; // 初始化状态,在构造器的时候赋值
private static final int COMPLETING = 1; // task执行完成的时候
private static final int NORMAL = 2; // task执行完毕的最终状态 set方法中
private static final int EXCEPTIONAL = 3; // throw exception的时候
private static final int CANCELLED = 4; // 取消任务,在线程执行之前尝试阻止run,通过该表state mayInterruptIfRunning = false
private static final int INTERRUPTING = 5; // only while interrupting the runner to satisfy a cancel(true) mayInterruptIfRunning = true
private static final int INTERRUPTED = 6; // be ibterrupted 中断
//可能出现的几种状态转换
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
2. cancel(boolean mayInterruptIfRunning)
public boolean cancel(boolean mayInterruptIfRunning) {
/**
在Task构造之后/run之前,尝试改变state状态,当mayInterruptIfRunning = true 为
INTERRUPTING false = CANCELLED。
当然,一般情况下都是task执行了, state != New,那么当确切想中断运行任务,mayInterruptIfRunning = true 会使得获取当前线程进行中断标识,最后将state改变为INTERRUPTED。
最后执行 《finishCompletion》
*/
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
3. finishCompletion()
/**
* Removes and signals all waiting threads, invokes done(), and
* nulls out callable.
* 这块是关键,无论cancel的 finally / get 的finally 都会执行该方法,这个方法的主要作用就是unpark waiters,
* 关键在于, get() 维护了一个 WaitNode 来记录哪些线程调用了,当Task Completion 时,会唤醒那些被阻塞等待的线程。
*/
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
//cas修改 waiters 的offset
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
//unpark 唤醒被阻塞的线程
LockSupport.unpark(t);
}
//往后挪
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
//做一些自定义的任务
done();
callable = null; // to reduce footprint
}
4. get 阻塞获取异步任务处理的结果
//一直阻塞等待,知道结果返回或抛出异常
public V get() throws InterruptedException, ExecutionException {
int s = state;
//如果s还没有执行完成
if (s <= COMPLETING)
// awaitDone
s = awaitDone(false, 0L);
return report(s);
}
/**
* @throws CancellationException {@inheritDoc}
* 超时时间,规定时间未返回,抛出异常
*/
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);
}
//根据状态返回Task的结果值或者抛出异常
private V report(int s) throws ExecutionException {
//outcome task result
Object x = outcome;
/** 这块为啥是NORMAL状态呢,因为NORMAL状态他表示当前任务的最终状态,
在run中,当任务执行完成之后,会将state的 COMPLETING 改变为 NORMAL,
可以说 NORMAL 是对外表示完成的状态,COMPLETING 则为对内完成的状态。
*/
if (s == NORMAL)
// 返回任务的结果值
return (V)x;
/** 如果是CANCELLED ,就是上面的cancel 为false的时候,会有该状态。
这个时候获取的时候就会抛出异常 这块的状态可能会有 CANCELLED INTERRUPTING INTERRUPT
*/
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
/**
* Awaits completion or aborts on interrupt or timeout.
*
* @param timed true if use timed waits
* @param nanos time to wait, if timed
* @return state upon completion
* get的主要逻辑
*/
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
//计算出deadline,即等待执行时间,0为等待
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
//自旋
for (;;) {
//判断当前调用该方法的线程是否被中断,如果被中断,则将该线程移除waiters,这块是自旋,在break之前会一直检测
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
//当task的state为 NORMAL 之后,(如果之前这个线程被加入节点等待)就会将当前waiters中的q线程直接null,不必去操作Node内其他变量。(removeWaiters会help一下)同时返回结果s,s会进过report最终会返回给调用者结果
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
// cpu调度,当前调用该方法的线程让出cpu执行权
Thread.yield();
else if (q == null)
q = new WaitNode();
///链表中新增waiters的节点
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
// 看看需不要处理等待时间的
else if (timed) {
//计算deadLine到当前时间的查询 deadLine = last.System.nanoTime() + nanos
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
//超时了,需要将等待的节点剔除
removeWaiter(q);
return state;
}
//继续阻塞
LockSupport.parkNanos(this, nanos);
}
else // s <= COMPLETING
LockSupport.park(this);
}
}
/**
* Tries to unlink a timed-out or interrupted wait node to avoid
* accumulating garbage. Internal nodes are simply unspliced
* without CAS since it is harmless if they are traversed anyway
* by releasers. To avoid effects of unsplicing from already
* removed nodes, the list is retraversed in case of an apparent
* race. This is slow when there are a lot of nodes, but we don't
* expect lists to be long enough to outweigh higher-overhead
* schemes.
* 移除等待的节点
*/
private void removeWaiter(WaitNode node) {
if (node != null) {
//先将当前node内的Thread变量置空
node.thread = null;
retry:
//自旋
for (;;) { // restart on removeWaiter race
// 挪掉节点中Thread为空的
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
if (q.thread != null)
pred = q;
else if (pred != null) {
pred.next = s;
if (pred.thread == null) // check for race
continue retry;
}
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
continue retry;
}
break;
}
}
}
5. run
/**
* task执行的方法
*/
public void run() {
//拿到当前执行run方法的线程, 如果状态不是NEW(这块在上面说到过,可以通过cancel阻止任务的执行)
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);
}
}
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
//正如之前所说, NORMAL为最终的状态
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
private void handlePossibleCancellationInterrupt(int s) {
// It is possible for our interrupter to stall before getting a
// chance to interrupt us. Let's spin-wait patiently.
if (s == INTERRUPTING)
//之前说过,INTERRUPTING是当cancel(true),此时,线程设置中断标识,假如在此刻之前,就已经被中断了,就需要等待 finally -- UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);更改当前task的状态。这块check状态改变
while (state == INTERRUPTING)
Thread.yield(); // wait out pending interrupt
// assert state == INTERRUPTED;
// We want to clear any interrupt we may have received from
// cancel(true). However, it is permissible to use interrupts
// as an independent mechanism for a task to communicate with
// its caller, and there is no way to clear only the
// cancellation interrupt.
//
// Thread.interrupted();
}
4.总结
- 这块可以通过总结一个时序图来加深对FutureTask的执行的流程。good bye