多线程基础(十三):java中的FutureTask

it2026-10-09  2

文章目录

1.类结构及常量、变量1.1 类结构1.2 常量1.3 变量 2.构造函数2.1 FutureTask(Callable callable)2.2 FutureTask(Runnable runnable, V result) 3.重要方法3.1 get()3.2 get(long timeout, TimeUnit unit)3.3 awaitDone3.4 cancel3.5 finishCompletion3.6 removeWaiter3.7 run3.8 runAndReset 4.内部类WaitNode5.总结 FutureTask源码分析

1.类结构及常量、变量

1.1 类结构

FutureTask类结构如下:

/** * A cancellable asynchronous computation. This class provides a base * implementation of {@link Future}, with methods to start and cancel * a computation, query to see if the computation is complete, and * retrieve the result of the computation. The result can only be * retrieved when the computation has completed; the {@code get} * methods will block if the computation has not yet completed. Once * the computation has completed, the computation cannot be restarted * or cancelled (unless the computation is invoked using * {@link #runAndReset}). * * <p>A {@code FutureTask} can be used to wrap a {@link Callable} or * {@link Runnable} object. Because {@code FutureTask} implements * {@code Runnable}, a {@code FutureTask} can be submitted to an * {@link Executor} for execution. * * <p>In addition to serving as a standalone class, this class provides * {@code protected} functionality that may be useful when creating * customized task classes. * * @since 1.5 * @author Doug Lea * @param <V> The result type returned by this FutureTask's {@code get} methods */ public class FutureTask<V> implements RunnableFuture<V> { }

可以看到,FutrueTask实现了RunnableFuture接口,而RunnableFuture接口又继承了Future和Runnable。如下图:

上述注释大意为: Future是一个可取消的异步计算框架,提供了Future接口的基本实现,其中包括start、cancel、query以查看计算是否完成以及检索计算结果的方法。只有在计算完成之后才能检索结果,如果计算尚未完成,则get方法将阻塞,一旦计算完成,就不能重新开始或者取消计算。除非使用runAndReset。 FutureTask可以用于包装Callable或者Runnable的对象。由于FutureTask实现了Runnable接口,可以将FutureTask提交给Executor进行执行。 除了单独使用之外,此类还提供了protected方法,支持扩展,这些方法在创建自定义的任务的时候可能会很有用。

另外还有修订说明: 这与依赖AbstractQueuedSynchronizer实现的早期版本不同,此类主要是为了避免用户对取消任务期间还保留中断状态,当前设计中的同步控制依赖于通过cas更新的状态字段来跟踪完成情况,以及一个简单的Treiber堆栈来保存等待线程。 样式说明:与往常一样,我们绕过了使用AtomicXFieldUpdaters的开销。而且直接使用的是UnSafe的内部函数。

1.2 常量

/** * 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;

此任务的运行状态中,最初为new,运行状态仅在set、setException和cancel方法中转换状态。在完成期间,状态可能会采用COMPLETING(正在设置结果时)或者INTERRUPTING(仅在满足cancel条件进行中断的时候)的瞬时值。从这些中间状态的转换使用低消耗的ordered/lazy 写入,因为值是唯一的,无法进一步修改。 我们可以看到状态的变化路径:

运行完成 NEW -> COMPLETING -> NORMAL运行异常 NEW -> COMPLETING -> EXCEPTIONAL运行取消 NEW -> CANCELLED运行中断 NEW -> INTERRUPTING -> INTERRUPTED 主要是上面四种。

1.3 变量

/** The underlying callable; nulled out after running */ private Callable<V> callable; /** The result to return or exception to throw from get() */ 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 */ private volatile WaitNode waiters;

变量整理出如下表:

变量类型说明callableCallable底层调用的callable,如果为空则停止outcomeObject调用get返回的结果或者抛出的异常runnervolatile Thread运行callable的线程,cas操作在其run()方法中waitersWaitNode等待线程的Treiber堆栈

2.构造函数

构造函数主要有两种,分别是callable和支持runnable。

2.1 FutureTask(Callable callable)

这个方法将根据传入的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) { //如果为空,则抛出NPE异常 if (callable == null) throw new NullPointerException(); this.callable = callable; //初始状态为NEW this.state = NEW; // ensure visibility of callable }

2.2 FutureTask(Runnable runnable, V result)

这个方法传入runnable,并返回result。runnable实际上并不支持返回值,Executors的callable方法做了特殊处理。

/** * 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) { //callable 通过Executors的callable方法来产生。 this.callable = Executors.callable(runnable, result); //初始方法。 this.state = NEW; // ensure visibility of callable }

3.重要方法

3.1 get()

public V get() throws InterruptedException, ExecutionException { int s = state; //如果不是完成状态 if (s <= COMPLETING) //通过awaitDone进入等待 s = awaitDone(false, 0L); //返回report方法 return report(s); }

get方法将会进入wait状态,具体实现是LockSupport的park方法。

3.2 get(long timeout, TimeUnit unit)

这个方法只是增加了一个超时时间。

public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { //为空则抛出异常 if (unit == null) throw new NullPointerException(); int s = state; if (s <= COMPLETING && //指定时间wait (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING) throw new TimeoutException(); return report(s); }

3.3 awaitDone

根据传入时间进行wait,如果时间为0,则无期限等待。

private int awaitDone(boolean timed, long nanos) throws InterruptedException { //根据timed得到deadline final long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; boolean queued = false; //死循环 for (;;) { //如果线程被打断,则移除等待,并抛出异常 if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); } //s为状态 int s = state; //如果s大于COMPLETING说明执行完成 if (s > COMPLETING) { if (q != null) q.thread = null; return s; } //反之 让出当前线程 else if (s == COMPLETING) // cannot time out yet Thread.yield(); //初始化waitNode else if (q == null) q = new WaitNode(); //采用cas的方式设置waiters 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); } }

可以看到FutureTask内部是采用 LockSupport.park来对提交任务的线程进行阻塞,使其进入WAIT状态。

3.4 cancel

此方法将取消task。

public boolean cancel(boolean mayInterruptIfRunning) { //判断state状态 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; //通过interrupt来解除阻塞 if (t != null) t.interrupt(); } finally { // final state //cas的方式修改state UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); } } } finally { //完成后操作 finishCompletion(); } return true; }

3.5 finishCompletion

执行完毕之后,删除并通知所有等待线程。

private void finishCompletion() { // assert state > COMPLETING; //循环遍历 for (WaitNode q; (q = waiters) != null;) { //采用cas的方式设置waiters为null if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) { //死循环 for (;;) { Thread t = q.thread; if (t != null) { q.thread = null; //执行完毕之后unpark LockSupport.unpark(t); } //清理链表 便于gc回收 WaitNode next = q.next; if (next == null) break; q.next = null; // unlink to help gc q = next; } break; } } //这个方法提供给后续回掉或者什么也不做,是一个扩展方法。 done(); callable = null; // to reduce footprint }

3.6 removeWaiter

尝试取消链接超时或中断的等待节点,以避免积累垃圾。内部节点在没有cas的情况下,不会拼接在一起,因为如果释放者无论如何遍历它们,都是无害的。为了避免从已删除的节点取消拆分的影响,在出现明显竞争的情况下将重新遍历该列表。当节点很多时,会导致非常慢。

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; } } }

3.7 run

这个方法是执行FrutureTask的主体方法。

public void run() { //如果不为new状态或者不为当前线程则返回 if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; //必须要callback不为空,且为new状态 if (c != null && state == NEW) { V result; boolean ran; try { //执行call方法 result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; //设置异常 setException(ex); } if (ran) //设置result 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); } }

3.8 runAndReset

在不设置计算结果的情况下执行计算,然后将此状态重置为初始状态,如果遇到异常和cancel,则会失败。它设计用于本质上执行多次的任务。

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; }

此方法在每一此执行完之后会清理状态,重置为new,被用来设计为重复执行。

4.内部类WaitNode

WaitNode是一个链表节点,将等待的线程进行记录。

/** * 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(); } }

5.总结

FutureTask并不复杂,实现了Future设计模式,实际上本质是做一个异步的处理,但是会让任务的提交者进入等待过程,直至任务执行完毕。之后获取到执行完毕的结果。

最新回复(0)