• FutureTask源码分析(JDK7)


    总览

        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}).
    

    FututeTask 是可取消的异步任务。这个类提供了 Future 的基本实现,通过这些实现的方法能够开始或取消任务、查询任务是否完成、获取任务结果。仅当任务完成时才能获取任务的结果;当任务未完成时, get() 会阻塞。一旦任务完成,任务不能被重启或取消(除非任务由 runAndReset() 来启动)。

    //@param <V> 是 get() 返回结果的类型
    public class FutureTask<V> implements RunnableFuture<V>
    

    和JDK7以前的版本的不同之处

    /*
      * Revision notes: This differs from previous versions of this 
      * class that relied on AbstractQueuedSynchronizer, mainly to 
      * avoid surprising users about retaining interrupt status during 
      * cancellation races. 
      * Sync control in the current design relies 
      * on a "state" field updated via CAS to track completion, along 
      * with a simple Treiber stack to hold waiting threads. 
      */
    

    和之前依赖AQS的版本不同的主要原因是,之前的版本在并发的情况下取消任务,可能会导致任务处于 interrupt 的状态。

    当前设计的同步控制依赖于通过CAS更新的 state 成员变量以及一个容纳等待线程的 Treiber stack 来追踪任务的完成情况。

    成员变量

    /**
     * The run state of this task, initially NEW.  The run state
     * transitions to a terminal state only in methods set,
     * setException, and cancel.  During comp letion, 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.
     * 此任务的运行状态,初始值是NEW。
     * 运行状态转换只可能在set(), setException()和cancel()方法中发生。
     * 任务正在完成时,状态可能处于 COMPLETING(正在设置outcome成员变量) 或 INTERRUPTING(当通过 
     * cancel(ture)中断运行线程时) 这2个中间状态(瞬时值)。
     * 
     * 可能发生的状态转换:
     * 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;
    
    /** The underlying callable; nulled out after run */
    //运行后将变为null
    private Callable<V> callable;
    /** The result to return or exception to throw from get() */
    //get()返回的结果或抛出的异常
    //非volatile,受state的读或写保护
    private Object outcome; // non-volatile, protected by state reads/writes
    /** The thread running the callable; CASed during run() */
    //运行当前callable的线程
    private volatile Thread runner;
    /** Treiber stack of waiting threads */
    //容纳等待线程的栈
    private volatile WaitNode waiters;
    

    构造函数

     /**
     * Creates a {@code FutureTask} that will, upon running, execute the
     * given {@code Callable}.
     * 创建一个在运行时会执行指定callable的FutureTask
     *
     * @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
    }
    
    /**
     * 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.
     * 创建一个在运行时执行指定Runnable的,能够令get()在成功完成时返回结果的FutureTask
     *
     * @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
    }
    

    成员方法

    
    
    public boolean isCancelled() {
        return state >= CANCELLED;
    }
    
    public boolean isDone() {
        return state != NEW;
    }
    
    /**
     * 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);
    }
    
    public boolean cancel(boolean mayInterruptIfRunning) {
        //只有在NEW状态的任务才可以被取消
        if (!(state == NEW && STATE.compareAndSet
              (this, 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
                    //设置为最终状态:被中断
                    STATE.setRelease(this, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }
    
    /**
     * @throws CancellationException {@inheritDoc}
     */
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }
    
    /**
     * @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);
    }
    
    /**
     * 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() { }
    
    /**
     * 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 (STATE.compareAndSet(this, NEW, COMPLETING)) {
            outcome = v;
            //设置最终状态:正常完成
            STATE.setRelease(this, NORMAL); // final state
            finishCompletion();
        }
    }
    
    /**
     * 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.
     * 导致任务将报告一个以值得throwable为原因的 ExecutionException,
     * 除非任务已经被设置结果或被取消。
     * 
     * <p>This method is invoked internally by the {@link #run} method
     * upon failure of the computation.
     * 这个是一个内部使用的方法,只在任务失败时由run()调用。
     *
     * @param t the cause of failure
     */
    protected void setException(Throwable t) {
        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
            outcome = t;
            STATE.setRelease(this, EXCEPTIONAL); // final state
            finishCompletion();
        }
    }
    
    public void run() {
        //以下2种情况直接返回:
        //1.状态不为NEW
        //2.CAS设置当前线程为任务运行线程失败
        if (state != NEW ||
            !RUNNER.compareAndSet(this, 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)
                    //这个方法会调用finishCompletion()改变任务状态
                    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
            // 防止cacel(true)的线程挂起导致中断不完全,
            // 从而处于Interrupting的中间状态。
            // 保证 interrupting 这出现在run和runAndSet方法中
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
    
    /**
     * 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.
     * 在不设置结果的前提下运行任务,然后将future设置成初始状态?
     * 当任务遇到异常或被取消,将会运行失败。
     * 
     * 此方法设计目的:服务那些本就需要执行多次的任务。
     * 在ScheduleThreadPoolExecutor中用到,因为里面的任务都是定时或周期执行的,需要被执行多次。
     * 
     * @return {@code true} if successfully run and reset
     */
    protected boolean runAndReset() {
        //仅仅指出和run()的不同之处
        if (state != NEW ||
            !RUNNER.compareAndSet(this, 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);
                }
                //这里没有调用set(),因此不会调用finishCompletion()改变任务状态
            }
        } 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;
    }
    
    /**
     * Ensures that any interrupt from a possible cancel(true) is only
     * delivered to a task while in run or runAndReset.
     * 保证 interrupting 这出现在run和runAndSet方法中。
     */
    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.
        // 若任务处于INTERRUPTING状态,自旋等待任务被完全中断,
        // 即等待转换到INTERRUPTED状态
        if (s == INTERRUPTING)
            while (state == INTERRUPTING)
                Thread.yield(); // wait out pending interrupt
    
        // assert state == INTERRUPTED;
    	// 到这里 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();
    }
    
    /**
     * 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(); }
    }
    
    /**
     * Removes and signals all waiting threads, invokes done(), and
     * nulls out callable.
     * 移除和通知所有等待的线程,调用done(),并移除callable。
     */
    private void finishCompletion() {
        // assert state > COMPLETING;
        // 此时 state > COMPLETING;
        
        //若等待线程栈非空
        for (WaitNode q; (q = waiters) != null;) {
            //CAS设置等待线程为null
            if (WAITERS.weakCompareAndSet(this, q, null)) {
                //迭代栈,唤醒所有非空线程
                for (;;) {
                    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
    }
    
    /**
     * 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 or at timeout
     * 			返回任务完成或任务超时的状态
     */
    private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        // The code below is very delicate, to achieve these goals:
        // - call nanoTime exactly once for each call to park
        // - if nanos <= 0L, return promptly without allocation or nanoTime
        // - if nanos == Long.MIN_VALUE, don't underflow
        // - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
        //   and we suffer a spurious wakeup, we will do no worse than
        //   to park-spin for a while
        long startTime = 0L;    // Special value 0L means not yet parked
        WaitNode q = null;
        //记录当前线程是否入栈排队
        boolean queued = false;
        for (;;) {
            int s = state;
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING)
                // We may have already promised (via isDone) that we are done
                // so never return empty-handed or throw InterruptedException
                Thread.yield();
            else if (Thread.interrupted()) {
                //若当前线程被中断,移出栈,抛出异常
                removeWaiter(q);
                throw new InterruptedException();
            }
            else if (q == null) {
                if (timed && nanos <= 0L)
                    return s;
                //创建栈节点
                q = new WaitNode();
            }
            else if (!queued)
                //节点CAS尝试入栈,若成功则此节点成为waiters
                queued = WAITERS.weakCompareAndSet(this, q.next = waiters, q);
            else if (timed) {
                //若需要超时等待的功能
                final long parkNanos;
                if (startTime == 0L) { // first time
                    //首次判断,记录开始时间
                    startTime = System.nanoTime();
                    if (startTime == 0L)
                        startTime = 1L;
                    parkNanos = nanos;
                } else {
                    long elapsed = System.nanoTime() - startTime;
                    if (elapsed >= nanos) {
                        //若超时则返回
                        removeWaiter(q);
                        return state;
                    }
                    //计算剩余等待时间
                    parkNanos = nanos - elapsed;
                }
                // nanoTime may be slow; recheck before parking
                if (state < COMPLETING)
                    //快速判断任务是否正在完成
                    LockSupport.parkNanos(this, parkNanos);
            }
            else
                //若不需要超时等待的功能,直接阻塞
                LockSupport.park(this);
        }
    }
    
    /**
     * 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) {
            //令当前节点的线程为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 (!WAITERS.compareAndSet(this, q, s))
                        //移除栈顶节点失败
                        continue retry;
                }
                break;
            }
        }
    }
    
    /**
     * Returns a string representation of this FutureTask.
     *
     * @implSpec
     * The default implementation returns a string identifying this
     * FutureTask, as well as its completion state.  The state, in
     * brackets, contains one of the strings {@code "Completed Normally"},
     * {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
     * "Not completed"}.
     *
     * @return a string representation of this FutureTask
     */
    public String toString() {
        final String status;
        switch (state) {
        case NORMAL:
            status = "[Completed normally]";
            break;
        case EXCEPTIONAL:
            status = "[Completed exceptionally: " + outcome + "]";
            break;
        case CANCELLED:
        case INTERRUPTING:
        case INTERRUPTED:
            status = "[Cancelled]";
            break;
        default:
            final Callable<?> callable = this.callable;
            status = (callable == null)
                ? "[Not completed]"
                : "[Not completed, task = " + callable + "]";
        }
        return super.toString() + status;
    }
    
    // VarHandle mechanics
    private static final VarHandle STATE;
    private static final VarHandle RUNNER;
    private static final VarHandle WAITERS;
    static {
        try {
            MethodHandles.Lookup l = MethodHandles.lookup();
            STATE = l.findVarHandle(FutureTask.class, "state", int.class);
            RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
            WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
        } catch (ReflectiveOperationException e) {
            throw new ExceptionInInitializerError(e);
        }
    
        // Reduce the risk of rare disastrous classloading in first call to
        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
        Class<?> ensureLoaded = LockSupport.class;
    }
    
    不准不开心。
  • 相关阅读:
    js产生随机数函数,js如何生成随机数
    Oracle11g-linux安装
    ORACLE的监听日志太大,客户端无法连接 BUG:9879101
    liunx下oracle链接数超出最大链接数处理方法
    mui中的a标签注意事项
    mui中点击按钮弹出层可供选择数据自动填充
    js中处理对象JSON.stringify()
    eval()函数
    linux常用命令(1)
    centos下载地址
  • 原文地址:https://www.cnblogs.com/iltonmi/p/14328273.html
Copyright © 2020-2023  润新知