一类介绍
FutureTask类实现了Runnable和Future类接口,定义一个可以被取消的异步计算任务,提供了开始和取消任务接口,当计算完成可以查询执行结果,如果任务没有完成,get接口会阻塞获取结果线程,
二 关键属性
- 任务状态
private volatile int state;
// 初始化 当前任务没执行
private static final int NEW = 0;
//当前任务正在结束,尚未完全结束,一种临界状态
private static final int COMPLETING = 1;
//任务正常结束
private static final int NORMAL = 2;
//执行任务时候,发生了异常,内部封装的 callable.run() 向上抛出异常了
private static final int EXCEPTIONAL = 3;
//任务被取消了
private static final int CANCELLED = 4;
//当前任务被中断了
private static final int INTERRUPTING = 5;
//任务已经被中断了
private static final int INTERRUPTED = 6;
任务的状态转换
//submit(runnable/callable) ,runnable使用装饰器包装成callable
private Callable<V> callable;
/** The result to return or exception to throw from get() */
//保存执行结果 :任务正常执行,outcome保存执行结果,callable.call()的返回值
//call()抛出异常。callable向上抛出异常,outcome保存异常
private Object outcome; // non-volatile, protected by state reads/writes
//任务被执行的期间,保存当前执行任务的线程对象引用
private volatile Thread runner;
/** Treiber stack of waiting threads */
//阻塞get结果的线程,头插法的单向链表
private volatile WaitNode waiters;
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
三 主要方法
- 构造方法,将runnable对象装饰为callable对象
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
//callable就是程序员自己实现的业务类
this.callable = callable;
// 设置当前任务状态为 NEW
this.state = NEW; // ensure visibility of callable
}
//将runnable装饰成callable
//返回值,为给定的result ,可以为Null
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
//创建RunnableAdapter对象
return new RunnableAdapter<T>(task, result);
}
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
//执行runnable.run
task.run();
//返回给定的结果
return result;
}
}
- run方法
执行任务,首先判断任务是否被其他线程执行过了,或者被取消或者中断了,如果没有当前线程执行任务。出现异常调用setException方法 ,没有出现异常调用set()方法
setException 和 set方法调用finishCompletion()方法
public void run() {
//方法不是初始状态,说明线程已经被其他线程执行,或者取消,或者中断 return
// cas替换线程,可能被其他线程抢先替换 return
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
//执行到这里,当前task一定是 NEW 状态,而且 当前线程也抢占TASK成功!
try {
//callable就是程序员自己封装逻辑的callable或者装饰后的callable
Callable<V> c = callable;
//条件一 c!=null 防止空指针异常
//条件二 :state==new 防止外部线程cancel掉当前任务
if (c != null && state == NEW) {
//返回值
V result;
//是否出现异常。true 没抛出异常
//false 抛出异常
boolean ran;
try {
//调用callable或者装饰后的runnable接口
result = c.call();
//true代码块执行成功
ran = true;
} catch (Throwable ex) {
//出现异常
result = null;
ran = false;
//set结果到outcome 改变任务状态
setException(ex);
}
if (ran)
//说明当前c.call正常执行结束了。
//set就是设置结果到outcome ,使得任务状态发生改变
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);
}
}
// 调用在run方法出现异常的时候
protected void setException(Throwable t) {
// cas替换线程的状态为COMPLETING,失败说明任务被取消或者中断了
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
//返回值结果为异常
outcome = t;
//case替换线程的状态为exceptional
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
//唤醒所有调用get()方法阻塞的线程
finishCompletion();
}
}
//方法被调用在run()方法执行成功时候
protected void set(V v) {
//使用CAS方式设置当前任务状态为 完成中..
//有没有可能失败呢? 外部线程等不及了,直接在set执行CAS之前 将 task取消了。 很小概率事件。
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
//将结果赋值给 outcome之后,马上会将当前任务状态修改为 NORMAL 正常结束状态。
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
//唤醒所有调用get()方法阻塞的线程
finishCompletion();
}
}
- cancel方法,当任务是new状态的时候,终止线程,或者中断线程,最后唤醒所有调用get()方法的线程
public boolean cancel(boolean mayInterruptIfRunning) {
//任务状态不是new状态不能被取消
//改任务状态为中断或者取消
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
//能执行到这里 说明任务是new状态
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
//执行当前线程有可能现在是null,是null 的情况是: 当前任务在 队列中,还没有线程获取到它呢。。
Thread t = runner;
//条件成立:说明当前线程runner,正在执行task
if (t != null)
//给线程一个中断信号, 如果线程会响应中断,会走中断逻辑。。
t.interrupt();
} finally { // final state
//设计线程状态为 中断完成。
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
//唤醒所有的get()阻塞线程
finishCompletion();
}
return true;
}
- finishComletion方法 ,方法在取消任务,中断任务,任务执行(不管是否出现异常)调用
private void finishCompletion() {
// assert state > COMPLETING;
//q指向waiters链表头节点。 //外层for循环终止防止有节点从链表中删除了
for (WaitNode q; (q = waiters) != null;) {
//使用cas设置 waiters 为 null 是因为怕 外部线程使用 cancel 取消当前任务 也会触发finishCompletion方法。 小概率事件。
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
//获取当前node阶段封装的thread
Thread t = q.thread;
//线程不为空
if (t != null) {
q.thread = null;//help gc
//唤醒当前节点的线程
LockSupport.unpark(t);
}
//next的下一个节点
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
done();
callable = null; // to reduce footprint
}
- 多个线程等待当前任务执行完成后的结果,如果任务尚未执行完,阻塞线程,正常情况下获取结果,非正常情况下抛出异常
public V get() throws InterruptedException, ExecutionException {
//获取当前任务状态
int s = state;
//条件成立:未执行,正在执行,正在完成 调用get的外部线程会被阻塞在get方法上。
if (s <= COMPLETING)
//返回task当前状态,可能当前线程在里面已经睡了一会了..
s = awaitDone(false, 0L);
return report(s);
}
//get()方法中调用,s线程状态
private V report(int s) throws ExecutionException {
//正常情况下,outcome 保存的是callable运行结束的结果
//非正常,保存的是 callable 抛出的异常。
Object x = outcome;
//正常执行结束,返回执行结果
if (s == NORMAL)
return (V)x;
//任务被取消了,中断 抛出异常
if (s >= CANCELLED)
throw new CancellationException();
//任务执行出错,抛出异常
throw new ExecutionException((Throwable)x);
}
- awaitDone方法
- 当先线程是否被其他线程使用中断方式喊醒,如果是抛出异常
- 判断任务的状态,已经有结果了,直接return
- 如果任务是快结束的状态,等等就好了
- 如果q是空,创建节点
- 如果q没有添加到链表中,就添加到链表中
- 如果设置了超时时间,看是否超时,超时直接返回,如果没有Park线程
- park线程
// timed //true 设置等待时间
// 超时时间
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
//设置超时时间
final long deadline = timed ? System.nanoTime() + nanos : 0L;
//引用当前线程 封装为WaitNode对象
WaitNode q = null;
//表示当前线程 有没有插入到链表头部
boolean queued = false;
for (;;) {
//条件成立:说明当前线程唤醒 是被其它线程使用中断这种方式喊醒的。interrupted()
//返回true 后会将 Thread的中断标记重置回false.
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
//假设当前线程是被其它线程 使用unpark(thread) 唤醒的话。会正常自旋,走下面逻辑。
//s 任务的状态
int s = state;
//说明当前任务已经有结果了
if (s > COMPLETING) {
// 条件成立:说明已经为当前线程创建过node了,此时需要将 node.thread = null helpGC
if (q != null)
q.thread = null;
//返回当前状态
return s;
}
//任务快完成了,这里让当前线程再释放cpu ,进行下一次抢占cpu。
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
//如果条件成立:第一次自旋,当前线程还未创建 WaitNode 对象,此时为当前线程创建 WaitNode对象
else if (q == null)
q = new WaitNode();
//条件成立:第二次自旋,当前线程已经创建了WaitNode对象,判断node对象是否入队列
else if (!queued)
//cas方法设置waiters引用指向 当前线程node,如果成功的,queued==true,否则,其他线程入队列了
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
//如果设置了超时时间
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
//将线程从链表中删除
removeWaiter(q);
return state;
}
//设置阻塞超时时间
LockSupport.parkNanos(this, nanos);
}
else
//当前get操作的线程就会被park了。 线程状态会变为 WAITING状态,相当于休眠了..
//除非有其它线程将你唤醒 或者 将当前线程 中断。
LockSupport.park(this);
}
}
- removeWaiter,当线程被中断,或者超时等待时候,调用这个方法,从链表中删除node
private void removeWaiter(WaitNode node) {
if (node != null) {
node.thread = null;
retry:
for (;;) { // restart on removeWaiter race
//q等于头节点
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
//case 1:线程不为空
if (q.thread != null)
pred = q;
//case 2:线程为空的情况,如果pred不为空,说明不是链表的头节点,直接将q的前节点的next指向q的后面节点
else if (pred != null) {
pred.next = s;
if (pred.thread == null) // check for race
continue retry;
}
//q节点的线程为null,且是头节点的情况,q的下一个节点替换头节点
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
continue retry;
}
break;
}
Doug Lea太强了!!!!!