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

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

@[toc] 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。如下图: image.png

上述注释大意为: 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;
复制代码

变量整理出如下表:

变量 类型 说明
callable Callable 底层调用的callable,如果为空则停止
outcome Object 调用get返回的结果或者抛出的异常
runner volatile Thread 运行callable的线程,cas操作在其run()方法中
waiters WaitNode 等待线程的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设计模式,实际上本质是做一个异步的处理,但是会让任务的提交者进入等待过程,直至任务执行完毕。之后获取到执行完毕的结果。

猜你喜欢

转载自juejin.im/post/7086412593929125918