目录
1.1 FutureTask(Callable callable)
1.2 FutureTask(Runnable runnable, V result)
1.3.4 指向传入的实现了Callable接口的对象索引 callable
1.3.6 一个带向链表结构的线程链表中的一个节点(此部分博主还不太明白)
1.4.5 get(long timeout, TimeUnit unit)
1.5.2 awaitDone(boolean timed, long nanos)
1.5.3 removeWaiter(WaitNode node)
1.5.5 handlePossibleCancellationInterrupt(int s)
1.6.2 setException(Throwable t)
FutureTask类实现了RunnableFuture接口相关功能。RunnableFuture接口源码解读
此类的对象可以看成是一个可以对任务进行一些操作的实体,或者封装。
FutureTask类中:
2个有参构造器。
6个public修饰的方法。
5个private修饰的私有方法。
4个protected修饰的方法
1个静态内部类。
1个静态代码块。
一.源码解读
先来看看此类的两个有参的构造器
1.1 FutureTask(Callable<V> callable)
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @throws NullPointerException if the callable is null
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
此构造器作用是传入一个实现了Callable接口的的任务类,初始化该FutureTask能操作的任务类。
1.2 FutureTask(Runnable runnable, V result)
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Runnable}, and arrange that {@code get} will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If
* you don't need a particular result, consider using
* constructions of the form:
* {@code Future<?> f = new FutureTask<Void>(runnable, null)}
* @throws NullPointerException if the runnable is null
*/
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
如上图此构造器的作用是传入一个实现了Runnable接口的任务类,并设置当此任务类运行完成后,任务类需要向调用此类的get方法的对象返回的 结果(result)。
此构造器会调用Executors类的静态方法 callable(Runnable task, T result) 如下图
/**
* Returns a {@link Callable} object that, when
* called, runs the given task and returns the given result. This
* can be useful when applying methods requiring a
* {@code Callable} to an otherwise resultless action.
* @param task the task to run
* @param result the result to return
* @param <T> the type of the result
* @return a callable object
* @throws NullPointerException if task null
*/
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
而此静态方法会返回一个实现了Executors中的静态内部类:RunnableAdapter。如下图
/**
* A callable that runs given task and returns given 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() {
task.run();
return result;
}
}
如上图可以看见,此类就是实现了Callable接口,使得实现Runnable的类也能获取返回值,虽然此返回值是初始化任务时设置的。之前只实现Runnable接口的类,线程执行完这些类后是不会有返回值的。此RunnableAdapter<T>也是对适配器模式的实现.
以上模块我们能知道,此构造器的作用就是让只实现了Runnable接口的任务类,也能拥有我们设置的result返回值。类型是个泛型。因此返回的对象很宽泛,并不是说只能返回字符串等。
由于当前FutureTask类实现了RunnableFuture接口,当然需要实现它对应的功能,看完构造器,我们来看看他public修饰的方法。来看看这些方法可以对传入的(实现了Callable或Runnable的)任务类做出那些操作。
以下对传入的任务类统称任务X(不论实现了什么接口的任务类)
1.3 FutureTask类的一些常量和属性
/**
* The run state of this task, initially NEW. The run state
* transitions to a terminal state only in methods set,
* setException, and cancel. During completion, state may take on
* transient values of COMPLETING (while outcome is being set) or
* INTERRUPTING (only while interrupting the runner to satisfy a
* cancel(true)). Transitions from these intermediate to final
* states use cheaper ordered/lazy writes because values are unique
* and cannot be further modified.
*
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
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;
在进入第1.4之前我们需要先了解一下此类的一些属性和字段。
上图的属性都被private修饰,意义它们是此类自己使用的属性,不对外暴露。
1.3.1 任务当前状态 state
首先第一个state,顾名思义,为当前任务X的状态。它被volatile修饰,意义是同时只能被一个线程操作他的状态。
注意注释中说明了只有这四种状态的变化:
1 * NEW -> COMPLETING -> NORMAL
2 * NEW -> COMPLETING -> EXCEPTIONAL
3 * NEW -> CANCELLED
4 * NEW -> INTERRUPTING -> INTERRUPTED
1.3.2 任务7种状态属性:
NEW:代表此任务X正在从调用start()方法到任务正在运行的状态。
COMPLETING:代表此任务X运行结束,返回结果的时候,此时结果还未装载到outcome字段中(下面会提到)。完成中!
NORMAL:代表任务X执行成功,outcome字段保存正常返回值。
EXCEPTIONAL:代表任务X执行抛异常,outcome字段保存异常信息。
CANCELLED:任务X从start()方法开始到任务运行完成之前,用户调用了cancel(false)方法。因为cancel(false)会允许正在执行任务的线程执行完任务。所以任务最后会被执行完。所以从cancel(false)方法被调用到任务执行完毕。任务状态都会被置为CANCELLED。 请参考future接口中cancel的定义:Future接口(源码解读)
INTERRUPTING:任务X从start()方法开始到任务运行完成之前,用户调用了cancel(true)方法。此方法会调用interrupt()方法把中断标志置为true。当线程轮询到此标志位为true时,会做相关操作,比如真正的中断线程。例如说执行return或其他操作,抛出异常等。有关interrupt()方法可以参考博客:(先做个假链接,这里我要是忘了写,你们要么提醒我一下,要么百度一下)。
而在调用cancel(true)方法到任务被中断之前,状态标志位为INTERRUPTING
INTERRUPTED:当线程被真正中断后,任务的状态标志为此标志。
1.3.3 存放返回结果 outcome:
/** The result to return or exception to throw from get() */
private Object outcome; // non-volatile, protected by state reads/writes
1.3.4 指向传入的实现了Callable接口的对象索引 callable
/** The underlying callable; nulled out after running */
private Callable<V> callable;
1.3.5 运行Callable的线程 runner
/** The thread running the callable; CASed during run() */
private volatile Thread runner;
1.3.6 一个带向链表结构的线程链表中的一个节点(此部分博主还不太明白)
/** Treiber stack of waiting threads */
private volatile WaitNode waiters;
1.4 6个Public修饰的方法
1.4.1 isCancelled()
当任务状态大于等于CANCELLED时,返回true。
public boolean isCancelled() {
return state >= CANCELLED;
}
1.4.2 isDone()
当任务状态只要不等于NEW时,返回true。由此可以说明,除了NEW的状态,都可视为任务已经运行完成了。至于完成成功与失败不做考虑。
public boolean isDone() {
return state != NEW;
}
1.4.3 cancel()
实现了future接口的方法,此FutureTask类实现了RunnableFuture接口,而RunnableFuture接口又继承了future接口。future接口中有cancel方法。
public boolean cancel(boolean mayInterruptIfRunning) {
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;
}
首先我们来看一下这个方法的第一个if判断:
当任务X当前状态不为NEW时,这里是个&&,因此后面的compareAndSwapInt方法并不会执行。
cancel方法直接返回false。
(1)意味着任务X当前的状态不为NEW时,不能使用cancel方法,cancel方法不会执行任何操作并返回false。
当任务X当前的状态为NEW时,我们再来看看这个方法。
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)
这个方法是Unsafe类的(native)本地方法。也是对CAS思想的实现。关于CAS:
/**
* Atomically update Java variable to <tt>x</tt> if it is currently
* holding <tt>expected</tt>.
* @return <tt>true</tt> if successful
*/
public final native boolean compareAndSwapInt(Object o, long offset,
int expected,
int x);
此方法的意思是,当存放对象o中偏移量为offset的值与期望值excepted相等时,把对象o中偏移量为offset的值修改为x。
至此我们返回上面的if判断:
(2)意味着任务X当前的状态为NEW时,且传入的mayInterruptIfRunning为false时。任务的状态被切换为CANCELLED
且继续运行try部分代码,此时mayInterruptIfRunning为false,所以直接执行finally代码块中的finishCompletion()方法:
这里我们转到1.5.9节。好了看完finishCompletion()方法我们知道了只要执行cancel方法,那么waiters链表中所有节点的任务都会被取消。
(3)意味着任务X当前的状态为NEW时,且传入的mayInterruptIfRunning为true时。任务的状态被切换为INTERRUPTING。并且告知线程需要被中断。执行了interrupt方法。这里我们继续来看看UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
/** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */
public native void putOrderedInt(Object o, long offset, int x);
这个方法也是一个本地方法,意味着让虚拟机去设置内存屏障,避免指令重排序。作用是把offset位置的值修改为x。而且只有当offset位置的值被volatile修饰时,它被更新为x后才能立即从工作内存刷新到主内存中,这里大家应该能发现1.3.1中state就是被volatile修饰的。这里我们需要了解JMM的知识。
当然在这里就是把状态更新为INTERRUPTED
看完上面3点,我们走完了1.3.1中第3种和第4种状态变化。
1.4.4 get()
/**
* @throws CancellationException {@inheritDoc}
*/
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
这方法是实现父接口的父接口future中的get方法。调用此方法的线程会阻塞到得到任务返回的结果。
里面用了awaitDone方法:请看1.6.1。
此方法意味着当任务未完成时才会去调用awaitDone的方法,看完1.6.1我们也知道,此方法会在大于COMPLETING时返回任务状态。其他状态要么yield要么park了。当大于COMPLETING状态时(可再次查看1.3.1查看状态变化)不进入awaitDone方法直接返回状态。因为只要完成之后,状态就更新了,可以直接返回状态。
1.4.5 get(long timeout, TimeUnit unit)
/**
* @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);
}
此方法和get无参方法差不多,只是当任务未结束时,已经到达了等待时间,那么会抛出超时异常。
1.4.6 run()
public void 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 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);
}
}
实现了接口的方法,此方法才是核心运行任务的方法,看源码,它首先判断任务是否为NEW,不为NEW就直接返回了,从此可知,重复运行run方法是没有用的,同一个任务只运行一次。
如果当前的执行Callable的线程runner为null,那么他会让当前线程去成为runner。执行Callable。这也是run的意义。当然如果不为null,已经有runner去执行任务了,那么也直接run方法也直接return。
try块中的代码就是执行Callable的call方法。并获取结果result。不抛异常就调用set方法,那么我们来看一下set方法:见1.7.1节
那么当抛出异常我们需要调用setException()方法:
1.5 5个private修饰的方法
1.5.1 finishCompletion()
此方法是私有的供FutureTask类自己使用,它的作用是释放waiters单链表中所有节点的线程和任务资源。
/**
* Removes and signals all waiting threads, invokes done(), and
* nulls out callable.
*/
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {//循环完所有waiters链表的节点,让线程置空,并唤醒它。
Thread t = q.thread;
if (t != null) {
q.thread = null;
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
}
在看这个方法的源码之前我们先看一下静态代码块部分,看完静态代码块部分我们看for循环,这个for循环首先定义一个WaitNode q,让他指向一个waiters节点,并且不能为空(这也是循环条件),;后不写任何自增的代码。接下来获取节点中的线程t,如果t不为空,那么让它变为空,接下来我们看看这个方法:LockSupport.unpark(t);
/**
* Makes available the permit for the given thread, if it
* was not already available. If the thread was blocked on
* {@code park} then it will unblock. Otherwise, its next call
* to {@code park} is guaranteed not to block. This operation
* is not guaranteed to have any effect at all if the given
* thread has not been started.
*
* @param thread the thread to unpark, or {@code null}, in which case
* this operation has no effect
*/
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
这方法就是对判断thread不为空才继续调用UNSAFE的unpark方法,我们再往下跟:
/**
* Unblock the given thread blocked on <tt>park</tt>, or, if it is
* not blocked, cause the subsequent call to <tt>park</tt> not to
* block. Note: this operation is "unsafe" solely because the
* caller must somehow ensure that the thread has not been
* destroyed. Nothing special is usually required to ensure this
* when called from Java (in which there will ordinarily be a live
* reference to the thread) but this is not nearly-automatically
* so when calling from native code.
* @param thread the thread to unpark.
*
*/
public native void unpark(Object thread);
看上图我们看见这又是一个native方法,此方法的作用是给传入此方法的thread线程一个许可,代表它可以苏醒了。不调用此方法,如果此方法调用了park方法,他将会一直被阻塞到park操作上。
继续回到上面的finishCompletion()方法。我们看见代码中q.thread = null; LockSupport.unpark(t);首先把节点的线程置空,再把线程唤醒,相当于是把节点线程的任务结束掉,再唤醒线程,那么线程就没有任务在执行了。继续往下看能知道后面的代码就是不断都往后遍历节点,并释放资源。把每个节点的next都置空也是为了JVM在进行可达性分析算法时,能回收掉相关资源。
在这里我们不要忘了回到上面的cancel方法。我们也许是从那里跳过来的。
1.5.2 awaitDone(boolean timed, long nanos)
此方法为一个等待任务执行结束并返回任务状态的作用。可以设置最大等待时间,超过等待时间,直接返回任务状态并结束任务。
/**
* 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
*/
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);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
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);
}
}
看以上源码能得知此方法通过传入的布尔变量timed判断是否要设置等待超时参数。timed为true时,通过当前系统时间加上传入的nano等待时长,得到死亡线时间,for循环中,先判断当前线程是否被中断,中断则移除任务节点,并报错。这里有removeWaiter()方法:请见1.5.3
如果未被中断,那么判断当前状态是否大于COMPLETING,大于时,返回任务状态,并释放线程。意味着当线程执行完成,如下图,awaitDone方法会返回正常或异常的状态。
代码继续往下看,当前状态是COMPLETING时,那么执行Thread.yield();让线程进入就绪状态与其他线程再次竞争运行机会。下面判断queue的状态,意味for死循环中只会执行一次 queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);这段代码。循环中没有让queue再变为false的代码。除非CAS失败,意思就是线程不断轮训查看waiters节点的状态,当任务完成后,就把waiters节点置空,并返回状态。如果设置了timed状态为true,那么当死亡线时间到达,会直接移除节点任务,并返回任务状态。最后,当以上所有状态都不满足时,此线程会被park方法阻塞。
这里记得返回get方法。此方法相当于就是对get方法的实现。
1.5.3 removeWaiter(WaitNode node)
这个方法的注释是:
让超时的或中断的节点unlink掉也就是从这个链表中取出。来避免累计垃圾。
当不使用CAS时,这些节点时不能分割的,所以当释放器去遍历时,是不会对链表有影响。
为避免已删除的节点分割对未分割节点的影响,链表会重新整理。整理的过程是缓慢的,所以链表不能过长以致超过整理所计划消耗的资源。
/**
* 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 = 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;
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;
}
}
}
1.5.4 report(int s)
/**
* Returns result or throws exception for completed task.
*
* @param s completed state value
*/
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
此方法就是获取任务状态,并判断,当任务为正常完成NORMAL时返回状态,当任务s大于等于CANCELLED时,那么也许是4,5,6。当小于CANCELLED时也许是3,为什么没有0和1呢因为private修饰的report方法在每次调用的时候都已经判断大于COMPLETING 了 所以。这个report确实是对的,当状态为EXCEPTIONAL 就报执行异常ExecutionException((Throwable)x)
并抛出x异常信息,因为之前我们提到当状态为EXCEPTIONAL 时,会把异常信息装到任务状态中。可见setException方法。
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;
1.5.5 handlePossibleCancellationInterrupt(int s)
/**
* Ensures that any interrupt from a possible cancel(true) is only
* delivered to a task while in run or runAndReset.
*/
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)
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();
}
1.6 4个protected修饰的方法
1.6.1 set()
/**
* Sets the result of this future to the given value unless
* this future has already been set or has been cancelled.
*
* <p>This method is invoked internally by the {@link #run} method
* upon successful completion of the computation.
*
* @param v the value
*/
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
看完上面的内容,相信大家对这个UNSAFE里的方法很熟悉了。那么set方法就是把NEW状态更新为COMPLETING,更新成功就把v结果值赋值给outcome,赋值完成后,再把状态更新为NORMAL。最后释放各种资源调用finishCompletion方法。见1.5.9节。
看完set方法,我们走完了1.3.1中第1种状态变化。
1.6.2 setException(Throwable t)
/**
* Causes this future to report an {@link ExecutionException}
* with the given throwable as its cause, unless this future has
* already been set or has been cancelled.
*
* <p>This method is invoked internally by the {@link #run} method
* upon failure of the computation.
*
* @param t the cause of failure
*/
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
如果我们看完了set方法再来看此方法,那么能知道它就是走的1.3.1节中的第二种状态。
相信看完这里我们已经走完了1.3.1节任务状态中的第4种状态。
1.6.3 done()
此方法是一个回调函数,虽然在本类中此方法没有任何实现,但是我们仔细观察会发现,此done方法在本类中被finishCompletion()方法释放所有资源后最后调用了(请见1.5.1)。然而finishCompletion()又被set方法(请见1.6.1)和setException(Throwable t)和cancel方法(请见1.4.3)调用。这3个方法我们看完就能知道他设置改变了1.3.1中说明会发生的4种状态变化。从而知道done方法会在每个流程走完的时候被调用,每种流程最后都调用了finishCompletion(),而finishCompletion()最后又会调用done。所以当子类实现此方法后,可以在这方法中写一些任务执行完需要执行的代码。finishCompletion()会去回调它。
/**
* Protected method invoked when this task transitions to state
* {@code isDone} (whether normally or via cancellation). The
* default implementation does nothing. Subclasses may override
* this method to invoke completion callbacks or perform
* bookkeeping. Note that you can query status inside the
* implementation of this method to determine whether this task
* has been cancelled.
*/
protected void done() { }
栗子:task是传入实现了Runnable或Callable的任务(类)。
FutureTask<Integer> future = new FutureTask<Integer>(task) {
@Override
protected void done() {
try {
System.out.println("任务执行完毕,执行结果为:" + get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
1.6.4 runAndReset()
此方法从名字上很好懂,运行并重置。此方法在本类中没有被任何其他方法调用。
先来看看它的注释:
在不设置结果的情况下执行计算,然后将此任务重置为初始状态,如果计算遇到异常或被取消,则无法执行此操作。这是为原本会执行多次的任务的需求而设计的。
意思就是当一个任务执行之后会改变一些运行前的环境,而不能重复运行任务,而这个方法就是保证每次run正常执行后,都能重置并再次运行。
/**
* Executes the computation without setting its result, and then
* resets this future to initial state, failing to do so if the
* computation encounters an exception or is cancelled. This is
* designed for use with tasks that intrinsically execute more
* than once.
*
* @return {@code true} if successfully run and reset
*/
protected boolean runAndReset() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
Callable<V> c = callable;
if (c != null && s == NEW) {
try {
c.call(); // don't set result
ran = true;
} catch (Throwable ex) {
setException(ex);
}
}
} 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
s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
return ran && s == NEW;
}
一下代码我们在run方法中解释过了,是保证当前只有一个线程在运行任务,不论换哪一个线程来执行任务,任务都只有一个任务。如果当前没有线程执行本任务,那么把任务类中记录的运行本任务线程的变量置为本线程(此变量被存放在本类偏移量为runnerOffset的位置)。就是说没有线程运行本任务那么就由我来。
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return false;
此方法对比run方法,他关键的地方就是没有调用set方法。而set方法做了啥呢(参见1.6.1节)?他相当于让任务状态进行了 4种状态的第一种:
NEW -> COMPLETING -> NORMAL
如果不调用set方法的话,任务状态始终是NEW。所以我们能知道。runAndReset()的核心功能是,在运行完成后并不改变此任务的状态。以此达到多次运行的效果,比如当前有个需求是运行此任务4次算完成任务。那么前3次我可以调用runAndReset(),最后以此调用run(),从run方法或runAndReset中我们是能知道只有当状态为NEW时,任务才会运行的。其他状态时都会直接return了。
补充一下,为什么其他状态我们不考虑呢?因为其他状态要么是中断要么就是取消了,要么是异常了。只有正常运行完成我们才会继续任务对吧。因此才会在返回时有判断 return ran && s == NEW;代表ran要是true运行成功,并且没有被取消和中断。s需要判断为NEW才算reset。
1.7 静态代码块
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long stateOffset;
private static final long runnerOffset;
private static final long waitersOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = FutureTask.class;
stateOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("state"));//获取当前k类中任务的状态属性偏移量
runnerOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("runner"));//获取当前执行Callable方法的线程的偏移量
waitersOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("waiters"));//获取k类的waiters等待线程节点偏移量
} catch (Exception e) {
throw new Error(e);
}
}
上面代码中可以看出,先获取到了FutureTask类的Class对象k。然后获取它的state属性,runner属性,waiters属性,的偏移量。这三个属性都能在类中源码看见。
1.8 静态内部类
本类中执行任务的线程等待链表的一个节点的构造类。
/**
* Simple linked list nodes to record waiting threads in a Treiber
* stack. See other classes such as Phaser and SynchronousQueue
* for more detailed explanation.
*/
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
二.类的使用实践
待完善...