FutureTask 学习记录
学习自《深入浅出java多线程》和网上一些文章
为啥使用他?
在很多⾼并发的环境下,有可能Callable和FutureTask会创建多次。FutureTask能够在⾼并发环境下确保任务只执⾏⼀次。
简单介绍
实现了RunnableFuture接口,该接口继承了Runnable, Future接口
简单使用案例![在这里插入图片描述](https://img-blog.csdnimg.cn/20210713171322889.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTEzMDIyNg==,size_16,color_FFFFFF,t_70)
FutureTask源码学习
基于jdk1.8,参考
https://blog.csdn.net/x526967803/article/details/111724062
继承结构
实现了RunnableFuture接口,该接口继承了Runnable, Future接口
一种可取消的异步计算。这个类提供了Future的一个基本实现,提供了启动线程和取消线程、查询计算是否完成以及检索计算结果的方法。只有在计算完成后才能检索结果;如果计算尚未完成,get方法将阻塞。一旦计算完成,就不能重新启动或取消计算(除非使用runAndReset调用计算)。
FutureTask可用于包装可调用或可运行的对象。因为FutureTask实现Runnable,FutureTask可以提交给执行者执行。
除了充当独立类之外,此类还提供了受保护的功能,这些功能在创建自定义任务类时可能很有用。
静态变量state
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
此任务的运行状态,最初是NEW。运行状态仅在方法set、setException和cancel中转换为终端状态。在完成期间,状态可能呈现完成(在设置结果时)或中断(仅在中断运行程序以满足cancel(true)时)的瞬时值。从这些中间状态到最终状态的转换使用更便宜的有序/延迟写入,因为值是唯一的,不能进一步修改。可能的状态转换:
NEW -> COMPLETING -> NORMAL 没有异常,也没有被取消
NEW -> COMPLETING -> EXCEPTIONAL执行过程发生异常
NEW -> CANCELLED 执行后被取消
NEW -> INTERRUPTING -> INTERRUPTED 被中断
其他重要变量
// 任务,运行完为null
private Callable<V> callable;
// 从get()返回的结果或抛出的异常
private Object outcome; // non-volatile, protected by state reads/writes
// 运行可调用函数的线程;在运行期间CAS
private volatile Thread runner;
// get方法阻塞的线程队列
private volatile WaitNode waiters;
构造方法
// callable 的构造方法,状态变为NEW
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
// 由runnable 和结果来 包装成一个callable,状态也要赋值为NEW
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
get()方法的等待队列
// 设计成了节点的样子,要阻塞的线程就是当前的线程
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
run() 方法
run()方法一般被Executor调用
public void run() {
// 如果状态不为NEW 或者 runner 不为null,直接结束, 如果是null,赋值为当前线程
// runner 旧值不为null,说明该FutureTask被赋值过运行线程,可能就不是头一次运行,这样能保证每个FutureTask只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,防止结束后再调用run
runner = null;
// 重读state,防止中断
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
需要注意,如果caller线程调用了cancel(true) 来中弄断线程执行,除非任务callable实现类call()中设计了响应中断,否则不会中断call()执行的。
run方法中的setException方法
// 结果赋值为异常,state赋值为EXCEPTIONAL
// state : NEW -> COMPLETING -> EXCEPTIONAL
protected void setException(Throwable t) {
// 读取这个FutureTask在内存中偏移量为stateOffset(即它的state),是否为NEW?如果是state赋值为COMPLETING(暂态)
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
set方法
// 结果赋能为正常结果,state赋能为NORMAL
// state : NEW -> COMPLETING -> NORMAL
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
get 方法
// 阻塞 等到state 转为COMPLETING 才能下一步
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
// 等待任务完成
s = awaitDone(false, 0L);
return report(s);
}
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);
}
其中awaitDone方法
//等待任务完成,或者被中断,或者超时
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
//是否设置超时时间了?如果没,deadline = 0L
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;//是否入队的标志
//死循环入队等待,fifo
for (;;) {
// 如果被中断,移除等待节点q
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
// 如果已经过了COMPLETING,返回state,并将该等待节点的线程设为null
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
// 如果正好是暂态COMPLETING,说明马上就要有结果了,正在set过程中,自旋等待。
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
// 等待节点为null,新任务,初始化为新的等待节点。
else if (q == null)
q = new WaitNode();
else if (!queued)
// 如果没有入队,CAS, 将新节点q加入等待队列的队首,并赋值给该等待队列
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);
}
}