本节内容 讲解FutureTask 类中的属性 及其内部几个重要方法:
- 构造方法
- run方法,任务执行 入口,一切的开始
- get方法,无参:获取任务执行结果,任务结束之前会阻塞。有参:在指定时间内尝试获取执行结果。若超时则抛出超时异常
- cancel方法,取消一个任务,并返回取消结果。参数表示是否中断线程。
目录
推荐课程:硬核手撕Java线程池FutureTask源码 小刘讲源码
ExecutorService threadPool
Future<?> submit(Runnable task);
线程池里面的submit 方法的参数就是Runnable,future会被封装成Futuretask:
先把Callable 和Runnable 转化为RunnableFuture
这里用的是适配器模式
FutureTask 的属性
// 表示当前task状态
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;
/** The underlying callable; nulled out after running
底层的调用;运行后为空 */
// submit(Runnable / Callable) runnable 使用 适配器模式 伪装成 Callable
private Callable<V> callable;
/** The result to return or exception to throw from get()
get()返回的结果或抛出的异常 */
// 正常情况下:任务正常执行结束,outcome保存执行结果。callable 返回值
// 非正常情况下:callable 向上抛出异常,outcome保存异常
private Object outcome; // non-volatile, protected by state reads/writes
/** The thread running the callable; CASed during run()
运行可调用对象的线程;下套管在运行() */
// 当前任务被线程执行区间,保存当前执行任务的线程对象引用
private volatile Thread runner;
/** Treiber stack of waiting threads
等待线程的Treiber堆栈 */
// 因为会有很多线程去get当前任务的结果,所以 这里使用了一种数据结构 stack 头插 头取 的一个队列。
private volatile WaitNode waiters;
demo
public class Main {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
Future future1 = threadPool.submit(new RunnableTask());
Future future2 = threadPool.submit(new CallableTask<Object>());
threadPool.execute(new Runnable() {
@Override
public void run() {
}
});
}
private static class RunnableTask implements Runnable{
@Override
public void run() {
}
}
private static class CallableTask<T> implements Callable {
@Override
public T call() throws Exception {
return null;
}
}
}
threadPool.submit(new RunnableTask()); :
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
FutureTask构造方法:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
// callable 就是程序员自己实现的业务类
this.callable = callable;
// 设置当前任务状态 为NEW = 0
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
//使用适配器模式 将Runnable转换为了 callable 接口,外部线程 通过get获取
//当前任务执行结果时,结果可能为 null 也可能为 传进来的值
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
run方法:
// submit(runnable/callable) -> newTaskFor(runnable) -> execute(task) pool
// 任务执行 入口
public void run() {
// 条件一:state != NEW 成立,说明当前task已经被执行过了 或者 被cancel 了,总之非NEW状态的任务,线程就处理不了。
// 条件二:!UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread())
// 条件成立:cas失败,当前任务被其它线程抢占了
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
// 执行到这里,当前task一定是NEW状态,而且 当前线程也抢占TASK 成功!
try {
// callable 就是程序员自己封装逻辑的callable 或者 装饰后的runnable
Callable<V> c = callable;
// 条件一:防止空指针
// 条件二:防止外部线程 cancel掉当前任务
if (c != null && state == NEW) {
// 结果引用
V result;
// true 表示callable.run 代码块执行成功 未抛出异常
// false 表示callable.run 代码块执行失败 抛出异常
boolean ran;
try {
//调用程序员自己实现的callable 或者 适配后的Runnable
result = c.call();
//c.call() 未抛出异常
ran = true;
} catch (Throwable ex) {
result = null;
//c.call() 抛出异常
ran = false;
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)
// 回头再说 讲了cancel()就明白了
handlePossibleCancellationInterrupt(s);
}
}
setException方法
protected void setException(Throwable t) {
// 使用CAS方式设置当前任务状态为 完成中 。表示当前任务正在结束,尚未完全结束
// 有没有可能失败呢?外部线程等不及了,直接在set执行CAS之前 将 task取消了。很小概率事件
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
// 引用的是callable 向上层抛出的异常
outcome = t;
// 将当前任务的状态 修改为EXCEPTIONAL
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
// 回头再说 讲了get再说
finishCompletion();
}
}
set方法:
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();
}
}
finishCompletion方法
private void finishCompletion() {
// assert state > COMPLETING;
// q指向waiters 链表的头节点
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;
//条件成立:说明当前线程不为null
if (t != null) {
//helpGC
q.thread = null;
//唤醒当前节点对应 的线程
// 在 get() 的awaitDone 方法中park的
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
//扩展
done();
//helpGC
callable = null; // to reduce footprint
}
get方法:
// 场景:多个线程等待当前任务 执行完成后的结果
public V get() throws InterruptedException, ExecutionException {
// 获取当前任务状态
int s = state;
// 条件成立:未执行,正在执行,正在完成。调用get 的外部线程会被阻塞在get方法上
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
//正常情况下,outcome 保存的是callable运行结束的结果
// 非正常,保存的是callable 抛出的异常
Object x = outcome;
//条件成立:当前任务正常结束
if (s == NORMAL)
//直接返回callable运算结果
return (V)x;
//被取消状态
if (s >= CANCELLED)
throw new CancellationException();
//执行到达,说明callable结构实现中,是有bug的
throw new ExecutionException((Throwable)x);
}
awaitDone方法
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
// 0 不带超时
final long deadline = timed ? System.nanoTime() + nanos : 0L;
// 引用当前线程 封装成waitNode对象
WaitNode q = null;
//表示当前线程 WaitNode对象 有没有 入队/压栈
boolean queued = false;
//自旋
for (;;) {
//当前线程唤醒
//条件成立:说明当前线程 是被其它线程使用中断 喊醒的
//返回true 后会将Thread的中断标记重置回false
if (Thread.interrupted()) {
//当前线程node出列
removeWaiter(q);
//get方式抛出异常
throw new InterruptedException();
}
//else 假设当前线程是被其它线程 使用unpark(thread)唤醒的话。会正常自旋,走下面逻辑
//获取当前任务最新状态
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)
// q.next = waiters:头插头取
// 当前线程node节点 next 指向 原队列的头节点 waiters 一直指向队列的头
//CAS方式设置waiters引用指向 当前线程node,成功的话 queued == true 否则,可能其它线程先你一步
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
//第三次自旋 (get方法是有参的,有超时时间)
else if (timed) {
//
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
//第三次自旋 (get方法无参,没有超时时间)
else
//当前get操作的线程就会被park了,线程状态会变成 waiting状态,相当于休眠了
//除非有其它线程将你召唤 或者 将当前线程中断
LockSupport.park(this);
//park了,会停在这里,unpark后又从这里开始执行
}
}
removeWaiter方法
private void removeWaiter(WaitNode node) {
if (node != null) {
//
node.thread = null;
retry:
//自旋
for (;;) { // restart on removeWaiter race
// 遍历所有节点
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
//
if (q.thread != null)
pred = q;
//说明此时q已经不是头节点了,并且当前q的thread 为null
else if (pred != null) {
pred.next = s;
if (pred.thread == null) // check for race
//退到最外层for
continue retry;
}
// 要删除的node是头节点
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
//退到最外层for
continue retry;
}
break;
}
}
}
cancel方法
public boolean cancel(boolean mayInterruptIfRunning) {
//条件一:state == NEW 当前任务处于运行中 或者 处于线程池 任务队列中
//条件二:UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)
// 条件成立:说明修改成功,可以去执行下面的逻辑了,否则返回false表示cancel失败
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
//执行当前FutureTask 的线程,有可能现在是null,
//是null说明当前任务还在队列中,还没有线程获取到它
Thread t = runner;
//条件成立:说明当前线程 runner,还在执行任务
if (t != null)
//给runner线程一个中断信号
//如果程序是响应中断 会走中断逻辑,如果不响应中断的 就什么也不会发生
t.interrupt();
} finally { // final state
//设置任务状态为中断完成
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
//唤醒所有get 阻塞的线程
finishCompletion();
}
return true;
}