文章目录
(一)关键概念点
1、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;
}
2、Callable简介
Callable也是一个带泛型的接口类,其中仅定义了一个带有返回值的call方法,主要是提供返回值。
public interface Callable<V> {
//主要是得到线程执行完后的返回值
V call() throws Exception;
}
3、FutureTask简介
FutureTask是一个实现RunnableFuture接口的实现类,其中RunnableFuture是继承于Future和Runnable接口; 一般线程执行都是使用继承Thread或实现Runnable接口中的抽象方法run,但是这种都是void类型,是没有返回值, 故如果执行线程后需要得到返回值时,FutureTask随之诞生,同时也是在使用线程池ThreadPoolExecutor的submit时更符合Runnable或Callable这类型的参数。
FutureTask实际上是适配器设计模式的体现,在类级别上直接实现RunnableFuture,间接上实现Runnable和Future接口,其内部更是使用Callable变量——callable,在构造方法中对其初始化,自身内部实现的run方法中进行调用callable中的call方法。
(二)FutureTask生命周期
1、FutureTask生命状态值
FutureTask生命周期主要是依靠state变量的值来实现转换。
private volatile int state;//定义state变量,初始值会被设置为New
private static final int NEW = 0;//初始状态(代表callable被赋值,也是线程执行完成run之前的状态)
private static final int COMPLETING = 1;//线程任务执行完毕时的状态
private static final int NORMAL = 2;//线程执行完任务将结果更新后的状态
private static final int EXCEPTIONAL = 3;//线程执行过程发生异常后的状态
private static final int CANCELLED = 4;//线程未被执行前就被取消(cancel方法)后的状态
private static final int INTERRUPTING = 5;//线程正在运行时被设置被中断后的状态
private static final int INTERRUPTED = 6;//线程中断完毕后的状态
2、FutureTask生命状态变化
state初始化为NEW,仅在set方法,setException方法和cancel方法中state才可以转变为终态,在任务完成前,state的值可能为COMPLETING或INTERRUPTING。
state有四种可能的状态转换:
(1)线程正常执行完毕:NEW -> COMPLETING -> NORMAL
(2)线程执行过程中发生异常:NEW -> COMPLETING -> EXCEPTIONAL
(3)线程初始化后未执行前就执行了cancel方法:NEW -> CANCELLED
(4)线程执行过程中被中断:NEW -> INTERRUPTING -> INTERRUPTED
3、其他辅助变量
/**
* The underlying callable; nulled out after running
* run运行时会调用其方法call(),并得到结果,任务结束够会被置为null
*/
private Callable<V> callable;
/**
* The result to return or exception to throw from get()
* 计算结果的存储变量,使用get获取值实际上获取该值(异常后是异常值)
* non-volatile, protected by state reads/writes
*/
private Object outcome;
/**
* The thread running the callable; CASed during run()
* worker thread 执行线程
*/
private volatile Thread runner;
/**
* Treiber stack of waiting threads
* 并发stack数据结构,FutureTask在任务执行前被多次get方法阻塞的线程。
*/
private volatile WaitNode waiters;
(三)FutureTask源码分析
1、构造方法
/**
* 接收一个Callable类型的参数对内部callable变量直接赋值
* state值初始化为New状态
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
/**
* 用Runnable参数和返回类型来构造callable变量,内部使用Executors中callable进行构造
* state值初始化为New状态
*/
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);//静态方法初始化,内含适配器模式
this.state = NEW; // ensure visibility of callable
}
Executors工具类:
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);//适配器构造
}
Executors工具类中的内部类:
//适配器类
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() {//实现Callable接口类中的接口
task.run();//统一调用FutureTask中的run方法
return result;
}
}
2、run方法(核心)
线程创建完毕后,第一种是将其提交给线程池来执行,第二种也可以自行使用start开启,无论那种方法最终都会执行FutureTask中的run方法,前者是call方法中使用task.run方法,后者更是重写run方法, FutureTask中的run方法内部都会调用Callable中call方法(该线程是使用Callable创建)。
/**
* 线程执行统一入口,无论Callable方式创建的线程或Thread或Runnable方式创建的,均由该处执行
* 保证线程只允许被执行一次且将结果缓存到outcome变量
*/
public void run() {
/**
* 判断线程是否被重复启用,只允许运行一次,条件如下:
* 条件一:线程状态不为初始状态,被执行者改变过状态
* 条件二:线程的执行者不为空,代表已有执行者
*/
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this,runnerOffset,null,Thread.currentThread()))
return;
/**
* 内部调用Callable中的call方法
* 执行call方法抛异常的处理方法setException
* 正常执行完毕状态更改方法set
*/
try {
Callable<V> c = callable;
if (c != null && state == NEW) {//满足正常执行条件
V result;
boolean ran;
try {
result = c.call();//适配器模式后的调用call方法
ran = true;//在正常得到返回值的前提下,保证能执行set方法
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);//异常时执行的方法
}
if (ran)//正常执行完线程call后的条件
set(result);//将结果缓存到outcome中
}
} finally {
runner = null;//执行者置空
// 线程是否被中断,如果被中断则需要改变状态
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
3、set方法
/**
* 在run中得到返回值后需要将结果缓存和唤醒阻塞线程
* set是改变state状态前后将结果缓存到outcome变量
* finishCompletion是唤醒阻塞线程
*/
protected void set(V v) {
//任务即将结束前的状态,CAS保证原子性,state是volatile类型
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;//将值赋值即缓存
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); //线程state的最终变量即正常结束的最后状态
finishCompletion();//
}
}
//唤醒阻塞线程
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {//遍历等待者
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {//cas将阻塞线程变量置空
for (;;) {//自旋唤醒所有阻塞线程
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);//唤醒线程,LockSupport请查看其他文章
}
WaitNode next = q.next;//后继节点
if (next == null)//直到所有线程唤醒完毕跳出循环
break;
q.next = null; // unlink to help gc
q = next;//重新赋值WaitNode
}
break;
}
}
done();//子类重写时自定义重写,默认为空实现
callable = null;//help GC
}
4、get方法(核心)
/**
* 获取返回值
* 如果run中的call方法未执行完则会阻塞awaitDone,反之则返回值report
*/
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)//判断线程任务是否完成,利用state值判定
s = awaitDone(false, 0L);//进行阻塞
return report(s);//返回值
}
/**
* awaitDone阻塞方法,参数timed和nanos主要是兼容超时阻塞和非超时阻塞
*/
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;//超时时间
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {//判断是否有中断标志
removeWaiter(q);//移除等待者(多个WaitNode时,内部是循环置空)
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {//for自旋时判断task状态是否大于1,若是则代表其他线程已经将任务执行完毕
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) //如果state为1,则代表其他线程正处在更新结果值,释放资源
Thread.yield();//释放线程资源
else if (q == null)//此时代表需要进行阻塞
q = new WaitNode();//创建等待者节点WaitNode
else if (!queued)//默认为false,会进行入队
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
LockSupport.park(this);//直接阻塞
}
}
/**
* 返回缓存值,基于state值即s
*/
private V report(int s) throws ExecutionException {
Object x = outcome;//内部核心变量缓存值outcome
if (s == NORMAL)//正常结束状态则返回
return (V)x;
if (s >= CANCELLED)//task状态大于等于3,代表状态异常
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
5、辅助方法(Future接口中的方法)
/**
* 通过state值与取消状态对比
*/
public boolean isCancelled() {
return state >= CANCELLED;
}
/**
* 通过state值与初始状态对比,不是NEW状态则代表完成,正常执行情况大部分为New状态,正在更新值状态可默认为完成
*/
public boolean isDone() {
return state != NEW;
}
/**
* 取消任务执行情况,包含未执行和正在执行两部分
* 传递一个布尔值对其任务更改,未执行状态则无论false还是true都返回true,
* 不同的是false是设置取消状态,true是设置为中断状态
* 传递一个布尔值对其任务更改,正在执行状态中传递true时会对其state状态更改未取消状态,
*/
public boolean cancel(boolean mayInterruptIfRunning) {
/**
* 此处会判断state值的改变情况:
* 第一种:task任务还没开始执行,会根据mayInterruptIfRunning进行中断还是取消状态改变
* 第二种:task任务执行完毕(标志为state不是NEW状态),则直接返回false
* 第三种:task在NEW的前提下,CAS失败时说明state在某一时刻改变,则表明任务发生其他变化,返回false,取消失败
*/
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 { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();//唤醒阻塞线程
}
return true;
}