java多线程 FutureTask源码分析

目录

简介

字段state,各种状态常量,callable,outcome,runner,waiters

方法report,2个构造函数,isCancelled,isDone,cancel,2个get

方法done,set,setException,run,runAndReset,handlePossibleCancellationInterrupt

内部类WaitNode,方法finishCompletion,awaitDone,removeWaiter,字段UNSAFE,3个Offset


简介

package java.util.concurrent;
import java.util.concurrent.locks.LockSupport;

/**
 * 一种可取消的异步计算。
 * 这个类提供了Future的一个基本实现,带有启动和取消计算、查询计算是否完成以及检索计算结果的方法。
 * 只有在计算完成后才可以检索结果;
 * 如果计算尚未完成,则get方法将阻塞。
 * 计算完成后,不能重新启动或取消计算(除非使用runAndReset调用计算)。
 *
 * <p>FutureTask可用于包装Callable或Runnable的对象。
 * 因为FutureTask实现了Runnable,所以可以将FutureTask提交给Executor执行。
 *
 * <p>除了作为一个独立的类,这个类还提供了受保护的功能,在创建自定义任务类时可能会很有用。
 * 
 * FutureTask整合了Callable对象,使得我们能够异步地获取task执行结果。
 * 执行FutureTask.run()的线程就相当于生产者,生产出执行结果给outcome。
 * 
 * 执行FutureTask.get()的线程就相当于消费者,它们会阻塞等待直到执行结果产生。
 * 如果生产者线程已经开始执行Callable.call(),那么消费者调用cancel,实际上是无法终止生产者的运行的。
 *
 * @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>

字段state,各种状态常量,callable,outcome,runner,waiters

    /*
     * 修订说明:这与依赖于AbstractQueuedSynchronizer的该类的以前版本不同,主要是为了避免在取消竞争期间保留中断状态让用户感到意外。
     * 当前设计中的同步控制依赖于通过CAS更新的“state”字段来跟踪完成,以及一个简单的Treiber堆栈来保存等待线程。
     *
     * 风格注意:像往常一样,我们绕过了使用AtomicXFieldUpdaters的开销,而是直接使用Unsafe的内在特性。
     */

    /**
     * 这个任务的运行状态,最初是NEW。
     * 只有在方法set、setException和cancel中,运行状态才会转变为终端状态。
     * 在完成过程中,状态可能呈现为COMPLETING(当结果被设置时)或INTERRUPTING(仅当中断运行以满足cancel(true))的瞬态值。
     * 从这些中间状态到最终状态的转换使用更便宜的有序/惰性写入,因为值是唯一的,不能进一步修改。
     * 
     * FutureTask的重点在于对task(Callable.call())的执行的管理,而FutureTask通过一个volatile的int值来管理task的执行状态。
     * 
     * 这种状态的转换都是不可逆的,某些过程中还可能存在中间状态,但这种中间状态存在的时间很短,且马上也会变成相应的最终状态。
     * 所以可以认为,只要状态不是NEW的话,就可以认为生产者执行task已经完毕。关于这一点,isDone函数可以替我作证:
     * 
     * 调用这些函数可以使得状态发生转移(具体过程后面讲解):
     * set(V v)使得NEW -> COMPLETING -> NORMAL。
     * setException(Throwable t)使得NEW -> COMPLETING -> EXCEPTIONAL。
     * 
     * cancel(boolean mayInterruptIfRunning)可能有两种状态转移:
     * 当mayInterruptIfRunning为false时,使得NEW -> CANCELLED。
     * 当mayInterruptIfRunning为true时,使得NEW -> INTERRUPTING -> INTERRUPTED。
     * 注意,图中的“取消”二字打了引号,因为消费者实际上不可能使得正在执行的生产者线程咔嚓终止掉。
     *
     * 可能的状态变化:
     * NEW -> COMPLETING -> NORMAL             正常执行完成
     * NEW -> COMPLETING -> EXCEPTIONAL     执行task途中抛出异常,与消费者无关
     * NEW -> CANCELLED                                    消费者取消了task
     * NEW -> INTERRUPTING -> INTERRUPTED   消费者取消了task,并且中断了生产者线程
     */
    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;

    /** 底层的调用;运行后为空 */
    private Callable<V> callable;
    
    /** 从get()返回的结果或抛出的异常 
     *   outcome是Object类型,可以存任何类型对象。这样既可以存泛型类型V,也可以存异常对象。
     * */
    private Object outcome; // non-volatile, 受状态读写保护
    
    /** 运行可调用对象的线程;
     *   当调用new Thread(FutureTask对象).start()时,生产者线程便创建并开始运行了,
     *   并且会在FutureTask#run()的刚开始就把生产者线程存放到runner中。
     * */   
    private volatile Thread runner;
    
    /** Treiber 栈中等待的线程  
     *   当调用FutureTask对象.get()时,如果task还未执行完毕,
     *   当前消费者线程会被包装成一个节点扔到栈中去。
     * */
    private volatile WaitNode waiters;


方法report,2个构造函数,isCancelled,isDone,cancel,2个get


    /**
     * 为已完成的任务返回结果或抛出异常。
     * 
     * 最后,我们再回到两个get函数的report(s),分析report()函数之前,先看看这个实参s可能是什么值。
     * 首先这个值是awaitDone调用后返回的。
     * 如果是无限阻塞地调用awaitDone,那么只可能返回s > COMPLETING的值。
     * 如果是超时阻塞地调用awaitDone,虽然可能返回NEW或COMPLETING,但是在get(long timeout, TimeUnit unit)中会马上抛出超时异常的。
     * 总之,实参s只能是s > COMPLETING的值。
     *
     * @param s completed state value
     */
    @SuppressWarnings("unchecked")
    private V report(int s) throws ExecutionException {
        Object x = outcome;//不管当前outcome是不是null,直接赋值
        if (s == NORMAL)//如果状态是NORMAL,则outcome肯定不是null
            return (V)x;
        if (s >= CANCELLED)//如果状态是取消的状态(这里其实不可能是INTERRUPTING)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);//如果状态是EXCEPTIONAL,那么抛出这个异常对象
    }


    /**
     * 创建一个FutureTask,在运行时执行给定的可调用对象。
     * 
     * 两个构造器都保证了初始时状态为NEW。
     * 除了可以接受Callable之外,还可以接受Runnable,
     * 但也是马上通过适配器模式把Runnable包装成一个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
    }

    /**
     * 创建一个FutureTask,在运行时执行给定的Runnable,并安排get在成功完成时返回给定的结果。
     *
     * @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;
    }

    /**
     *  之前说过,消费者实际上不可能使得正在执行的生产者线程咔嚓终止掉,接下来将解释。
     *  我们先来回顾一下,生产者线程在run函数中,直到执行set或setException之前,
     *  都在正常执行task中,而既然没有执行这两个函数,说明这段时间state还是为NEW的。
     *  
     *  而cancel函数执行前提就是state是NEW,在生产者线程执行set或setException之前,都是可以CAS成功的。
     *  
     *  如果消费者是在生产者线程执行run方法的if (c != null && state == NEW)之前就执行了cancel函数,那么才可以终止生产者执行task。
     *  
     *  如果消费者是在生产者线程执行run方法的if (c != null && state == NEW)之后才执行的cancel函数,那么将不能终止生产者。
     *  
     *  如果参数是false,state从NEW修改为CANCELLED。但修改state,并不能使得生产者线程运行终止。
     *  
     *  如果参数是true,state从NEW修改为INTERRUPTING,中断生产者线程后,再修改为INTERRUPTED。
     *  我们知道,中断一个正在运行的线程,线程运行状态不会发生变化的,只是会设置一下线程的中断状态。
     *  也就是说,这也不能使得生产者线程运行终止。除非生产者线程运行的代码(Callable.call())时刻在检测自己的中断状态。
     *  
     *  那你可能会问,这种情况既然不能真的终止生产者线程,那么这个cancel函数有什么用,其实还是有用的:
     *  
     *  如果参数为true,那么会去中断生产者线程。但生产者线程能否检测到,取决于生产者线程运行的代码(Callable.call())。
     *  状态肯定会变成CANCELLED或INTERRUPTED,新来的消费者线程会直接发现,然后在get函数中不去调用awaitDone。
     *  对于生产者线程来说,执行task期间不会影响。但最后执行set或setException,会发现这个state,然后不去设置outcome。
     *  最后执行了finishCompletion函数,唤醒所有的消费者线程。
     *  
     *  另外,注意,多个消费者来调用cancel函数,最多只有一个能够成功,即返回true。
     */
    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
                	// 在实现中可以看到有时候使用普通写的语义,有时候使用CAS写。
                	// 比如cancel函数中的UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED)这里使用的普通写,其他线程可能不能马上看到,但这没关系。因为:
                	// 一来,这个状态转移是唯一的。INTERRUPTING只能变成INTERRUPTED。其他线程暂时看不到 INTERRUPTED 也没关系。
                	//(注意,暂时看不到 INTERRUPTING,会导致handlePossibleCancellationInterrupt自旋)
                	// 二来,finishCompletion中也有对其他volatile字段的CAS写操作。这样做会把之前的普通写都刷新到内存中去。
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }

    /**
     * @throws CancellationException {@inheritDoc}
     */
    public V get() throws InterruptedException, ExecutionException {
    	// 此函数判断当前state,并根据情况调用awaitDone进行阻塞等待。
    	
    	// 如果state为NEW,那么生产者还没开始执行呢,肯定得阻塞等待。
    	
    	// 如果state为COMPLETING,那么生产者线程马上执行完了,
    	// 并且是 生产者正常执行完的过程(即前两种状态转移),那么也阻塞等待,即使马上会被唤醒。
        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 {
    	// 而这个函数是get的超时版本,所以调用awaitDone的实参设置不一样。
    	// 并且在退出awaitDone函数时,要检查返回值。
    	
    	// 返回值总是state的最新值:
    	// 如果state为NEW,那么说明返回是因为超时,因为生产者执行task期间state一直都为NEW(直到执行了set或setException才会改变),
    	// 所以说明返回时,要么生产者还没执行完task,要么生产者根本还没开始执行。
    	
    	// 如果state为COMPLETING,那么说明生产者即将执行完毕,但还没有设置返回值。虽然运气不好,但也只好算作超时。
        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);
    }


方法done,set,setException,run,runAndReset,handlePossibleCancellationInterrupt


    /**
     * 当任务转换到状态isDone时调用的受保护方法(无论是正常还是通过取消)。
     * 默认的实现不做任何事情。子类可能会覆盖这个方法来调用补全回调或执行bookkeeping。
     * 注意,您可以在此方法的实现中查询状态,以确定此任务是否已取消。
     */
    protected void done() { }

    /**
     * 将该future的结果设置为给定的值,除非该future已经被设置或取消。
     *
     * <p>此方法在计算成功完成后由run方法在内部调用。
     * 
     * 如果顺利执行完task,outcome会被赋值为执行结果。
     * 另外,状态转移是NEW -> COMPLETING -> NORMAL的过程,并且这个中间状态是只存在很短的时间的。
     *
     * @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();
        }
    }

    /**
     * 使这个future以给定的throwable作为它的原因来报告一个ExecutionException,
     * 除非这个future已经被设置或者被取消了。
     *
     * <p>此方法在计算失败时由run方法内部调用。
     * 
     * 如果执行task途中抛出异常,outcome会被赋值为抛出的异常对象。
     * 另外,状态转移是NEW -> COMPLETING -> EXCEPTIONAL的过程,并且这个中间状态是只存在很短的时间的。
     *
     * @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();
        }
    }

    public void run() {
    	// 在函数的一开始,需要检测state是否为NEW,且当前线程对象需要占领runner,并且在退出run函数之前,一直都会占领着runner。
        if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
            return;
        //执行到这里,说明此时state为NEW,且生产者位置已经被当前线程占领
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {  //直到这里,还会检查一次state是否为NEW
            	// 如果为NEW,就开始执行task。生产者自己执行task时(c.call()),有两种情况:
            	// 顺利执行完task,然后调用set(result)。
            	// 执行task途中抛出异常,然后调用setException(ex)。
                V result;
                boolean ran;
                try {
                    result = c.call();  // 执行task
                    ran = true;
                } catch (Throwable ex) {  // 生产者自身执行task过程中,抛出了异常
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)  // 生产者顺利执行完了task
                    set(result);
            }
        } finally {
        	// 最后还有finally块,先执行runner = null,执行后不用担心FutureTask对象.run()被调用两次,因为此时state肯定不是NEW了,run方法的第一句肯定通不过。
            // 再判断当前是否为>= INTERRUPTING,这种情况可能是遇到了state的中间状态,
            // NEW -> INTERRUPTING -> INTERRUPTED,所以需要调用handlePossibleCancellationInterrupt自旋等待直到最终状态。
            runner = null;          
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }


    /**
     * 在不设置结果的情况下执行计算,然后将这个future重置为初始状态,
     * 如果计算遇到异常或被取消,则不能这样做。
     * 这是为那些本质上执行多次的任务而设计的。
     *
     * @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;
    }

    /**
     * 确保来自可能的cancel(true)的任何中断只在运行或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();
    }


内部类WaitNode,方法finishCompletion,awaitDone,removeWaiter,字段UNSAFE,3个Offset


    /**
     * 在Treiber栈中记录等待线程的简单链表节点。
     * 请参阅其他类,如Phaser和SynchronousQueue获得更详细的解释。
     * 
     * 前面提到,对同一个FutureTask对象调用get的不同线程的都属于消费者,
     * 当生产者还没有执行完毕task时,调用get会阻塞。
     * 而做法是将消费者线程包装成一个链表节点,
     * 放到一个链表中,等到task执行完毕,再唤醒链表中的每个节点的线程。
     * 
     * 这种做法类似于AQS的条件队列和signalAll。
     * 反正最终链表上的所有节点都将被唤醒,所以链表是栈的逻辑结构,这样只用保存栈顶head指针,稍微简单一点。
     */
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }

    /**
     * 移除并通知所有等待的线程,调用done(),并使callable为空。
     * 
     * 由set和setException方法调用
     */
    private void finishCompletion() {
        // 保证调用此函数时,state > COMPLETING;
    	
    	// 此函数负责唤醒所有消费者线程,原理很简单,内层循环遍历链表的每个节点,唤醒每个节点的线程对象。
    	// 而外层循环在刚开始时,负责给局部变量q赋值,在退出外层循环时,负责检查waiters是否已经被赋值为null(当然检查结果肯定成立)。
        for (WaitNode q; (q = waiters) != null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, 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函数,但这只是空实现,这是用来给使用者拓展用的,可以让生产者线程在执行完毕前多做一点善后工作。
        done();

        callable = null;        // to reduce footprint
    }

    /**
     * 等待完成或在中断或超时时中止。
     *
     * @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 (;;) {
            	// 刚开始检查消费者线程的中断状态,如果被中断,说明消费者线程不应该再等待了。
            	// 那么从栈中移除节点,并抛出中断异常。比如消费者线程在LockSupport.park(this)后被中断而唤醒。
                if (Thread.interrupted()) {  //消费者线程被中断
                    removeWaiter(q);
                    throw new InterruptedException();
                }

                int s = state;  //获取最新的state
                // 接下来检查当前state是什么(可能是 第一次循环执行到这里,也可能是 阻塞后被唤醒下一次循环执行到这里),分为两种情况:
                // 如果是NORMAL或EXCEPTIONAL,说明生产者正常执行完task,没有受到消费者的取消动作干扰。这两种都是最终状态,直接返回即可。
                // 如果是CANCELLED、INTERRUPTING、INTERRUPTED,那么说明别的消费者“取消”了task。其中有一种中间状态,这无所谓,因为这三种状态都代表了取消。
                // 另外,这里是return s返回局部变量,而不是return state返回最新成员。因为大部分状态都是最终状态,即使有一个中间状态,它的最终状态也是已知的了。
                
                // 注意,返回的是return state,这里其实除了返回NEW以外,其他state也是都是可能返回的,在调用removeWaiter(q)期间可能会发现一些事情。
                // 比如,在此期间,生产者线程正在执行set,那么state可能是COMPLETING或NORMAL;
                // 比如,在此期间,别的消费者线程正在执行cancel,那么state可能是CANCELLED、INTERRUPTING、INTERRUPTED。
                // 关于上面这一点,其实就是给已经超时的超时操作多个机会,说不定执行完removeWaiter(q),state就变成NORMAL了呢。
                if (s > COMPLETING) {
                    if (q != null)
                        q.thread = null;
                    return s;
                }
                else if (s == COMPLETING) // 正常执行完的中间状态,自旋等待
                    Thread.yield();
                
                // 接下来就是正常阻塞前的流程:
                // 发现state还是NEW,所以新建节点。
                // 新建节点后,发现还没有入队,那么入队。
                // 入队完毕后,当前线程就可能马上阻塞了。
                else if (q == null)  // state为NEW,说明生产者线程还没执行完
                    q = new WaitNode();
                else if (!queued)  // 节点已经创建,但还没入栈
                    queued = UNSAFE.compareAndSwapObject(this, waitersOffset,//CAS保证了入栈的正确性
                                                         q.next = waiters, q);//先把新节点q的next指向旧栈顶,然后更新栈顶为q
                
                // 此时节点已经入队,但是state还是NEW,只能阻塞等待了
                // 阻塞根据参数有两种版本:
                // 无限阻塞。直接调用LockSupport.park(this)。
                // 超时阻塞。先计算得到剩余时间还有多少(正常阻塞前的流程也会花点时间的),然后调用LockSupport.parkNanos(this, nanos)。
                // 注意,如果超时阻塞后因为超时而唤醒时,也会走到这里,然后发现已经超时,那么栈中移除节点,并返回最新state。
                else if (timed) {  //如果是超时版本
                    nanos = deadline - System.nanoTime();  //获得剩余时间
                    if (nanos <= 0L) {  //剩余时间小于等于0,说明已经超时,但task还没执行完。
                        removeWaiter(q);
                        return state; //注意这里返回的不是局部变量,而是最新值。运气好的话,可能返回的不是NEW
                    }                    
                    LockSupport.parkNanos(this, nanos);
                }
                else
                    LockSupport.park(this);
            }
        }


    /**
     * 尝试断开超时或中断的等待节点的链接,以避免垃圾累积。
     * 在没有CAS的情况下,内部节点可以简单地不拼接,因为如果由释放器遍历它们,这是无害的。
     * 为了避免从已经删除的节点中取消拼接的影响,在使用可见跟踪时将重新遍历列表。
     * 当有很多节点时,这是缓慢的,但我们不希望列表足够长,以超过较高的开销方案。
     * 
     * 来看一下removeWaiter(q)是怎么移除节点的,注意实参是可能为null的,当q局部变量还没创建,当前线程就被中断时。
     */
    private void removeWaiter(WaitNode node) {
    	// 如果实参为null,那么啥也不做
        if (node != null) {
        	// 此函数参数node的thread被标记为null后,node就没有作用了。
        	// 因为遍历过程中,我们是去寻找所有的被标记的节点,然后尝试移除它们。
        	// 如果发现一个取消节点是首节点,那么使得head下移一个节点即可。
        	// 如果发现一个取消节点不是首节点,那么将pred -> q -> s变成pred -> s(执行pred.next = s)。如下图所示,从链表任意节点出发,都不能到达这个q节点。
        	// pred -> q -> s    变成     pred ->  s   q -> s
            node.thread = null; 
            retry:
            for (;;) {          // 致力于寻找pred -> q(thread == null) -> s的结构
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    s = q.next;
                    if (q.thread != null)  //发现q是未取消节点,更新pred和q
                        pred = q;
                    // 发现q是取消节点,但有两种情况
                    else if (pred != null) {  // 如果q不是首节点
                        pred.next = s;  //将pred -> q -> s变成 pred -> s
                        
                        // 不过有时候执行pred.next = s其实是一个无效操作,实际上并没有把q移除,此时需要重新开始循环continue retry
                        //(关于这一点,LinkedTransferQueue#unsplice也有一样的判断)。
                        // 这种情况是pred是一个取消节点时,如下图所示,q节点还是处于链表中:
                        if (pred.thread == null) // 如果发现pred也是一个取消节点,这说明q还在链表中
                            continue retry;
                    }
                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,  //如果q是首节点
                                                          q, s))  //那就使得栈顶下移一个节点即可
                        continue retry;
                }
                break;
            }
        }
    }


    // 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"));
            runnerOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("runner"));
            waitersOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("waiters"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值