死磕源码系列 - FutureTask

FutureTask相较于传统线程Thread就是可以阻塞等待返回线程执行结果, 这点在有些场景下是非常重要的.

那么来看下并发大神Doug Lea是如何实现的吧.

继承关系 - Future接口

先看类注释

A {@code Future} represents the result of an asynchronous computation.  Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation.    

-- Future 代表一个异步计算的结果, 此接口提供如下方法: 1.判断计算是否完成; 2.等待计算完成; 3.返回计算结果

The result can only be retrieved using method {@code get} when the computation has completed, blocking if necessary until it is ready.

-- 这个计算结果只能被 {@code get} 返回, 当计算完成或必要的阻塞直到其准备好(去返回).

Cancellation is performed by the {@code cancel} method.  Additional methods are provided to determine if the task completed normally or was cancelled. 

-- 取消任务需要调用 {@code cancel} 方法,其他的方法({@code isCancelled}, {@code isDone})用于判断此任务是否完成或被取消

Once a computation has completed, the computation cannot be cancelled.

-- 不能取消一个已经完成的任务

If you would like to use a {@code Future} for the sake of cancellability but not provide a usable result, you can declare  types of the form {@code Future<?>} and return {@code null} as a result of the underlying task.
    
-- 如果只是想使用其可取消而不使用其返回结果, 那么可以声明 {@code Future<?>} 类型并以 {@code null} 作为其底层任务返回值 返回.

然后提供了两种用法:

  • ArchiveSearcher
interface ArchiveSearcher { String search(String target); }

class App {

  ExecutorService executor = ...
  ArchiveSearcher searcher = ...
  
  void showSearch(final String target) throws InterruptedException {
    Future<String> future = executor.submit(new Callable<String>() {
        public String call() {
            return searcher.search(target);
        }
    });
    displayOtherThings(); // do other things while searching
    try {
      displayText(future.get()); // use future
    } catch (ExecutionException ex) { 
        cleanup(); 
        return; 
    }
  }
}
  • FutureTask
FutureTask<String> future = new FutureTask<String>(new Callable<String>() {
    public String call() {
      return searcher.search(target);
    }
});
  
executor.execute(future);

最后一段有点没看懂, 内存一致性: 异步计算的get()方法由另一个线程调用

 <p>Memory consistency effects: Actions taken by the asynchronous computation
 <a href="package-summary.html#MemoryVisibility"> <i>happen-before</i></a>
 actions following the corresponding {@code Future.get()} in another thread.

Future接口提供了五个方法

/**
 * Attempts to cancel execution of this task.  This attempt will
 * fail if the task has already completed, has already been cancelled,
 * or could not be cancelled for some other reason. If successful,
 * and this task has not started when {@code cancel} is called,
 * this task should never run.  If the task has already started,
 * then the {@code mayInterruptIfRunning} parameter determines
 * whether the thread executing this task should be interrupted in
 * an attempt to stop the task.
 *
 * <p>After this method returns, subsequent calls to {@link #isDone} will
 * always return {@code true}.  Subsequent calls to {@link #isCancelled}
 * will always return {@code true} if this method returned {@code true}.
 *
 * @param mayInterruptIfRunning {@code true} if the thread executing this
 * task should be interrupted; otherwise, in-progress tasks are allowed
 * to complete
 * @return {@code false} if the task could not be cancelled,
 * typically because it has already completed normally;
 * {@code true} otherwise
 */
boolean cancel(boolean mayInterruptIfRunning);

/**
 * Returns {@code true} if this task was cancelled before it completed
 * normally.
 */
boolean isCancelled();

 /**
 * Returns {@code true} if this task completed.
 *
 * Completion may be due to normal termination, an exception, or
 * cancellation -- in all of these cases, this method will return
 * {@code true}.
 *
 * @return {@code true} if this task completed
 */
boolean isDone();

/**
 * Waits if necessary for the computation to complete, and then
 * retrieves its result.
 *
 * @return the computed result
 * @throws CancellationException if the computation was cancelled
 * @throws ExecutionException if the computation threw an
 * exception
 * @throws InterruptedException if the current thread was interrupted
 * while waiting
 */
V get() throws InterruptedException, ExecutionException;

/**
 * Waits if necessary for at most the given time for the computation
 * to complete, and then retrieves its result, if available.
 *
 * @param timeout the maximum time to wait
 * @param unit the time unit of the timeout argument
 * @return the computed result
 * @throws CancellationException if the computation was cancelled
 * @throws ExecutionException if the computation threw an
 * exception
 * @throws InterruptedException if the current thread was interrupted
 * while waiting
 * @throws TimeoutException if the wait timed out
 */
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;

其注释也写的很清楚, 这里挑几点说一下:

  1. cancel()
  • 此方法将在以下情况下失败(注意这里没有未启动的状态)

    • 已经完成
    • 已经取消
    • 其他无法被取消的原因 (这个没再细说感觉有点迷的~)
  • 如果取消任务成功, 而此任务尚未启动, 则此任务永远不应进入运行

  • 此方法返回true后, 再调用{@link #isDone}{@link #isCancelled} 都会返回true

  • mayInterruptIfRunning这个参数就是其语义, 是否要中断已经启动的任务

  1. isDone()

返回true有以下几种情况

  • normal termination 正常结束
  • an exception 执行异常
  • cancellation 任务被取消
  1. get()get(long timeout, TimeUnit unit)

就是要等待任务完成(阻塞blocking)并返回其结果, 后者带超时时间.

实现类 - FutureTask

结构

public class FutureTask<V> implements RunnableFuture<V>

    - public interface RunnableFuture<V> extends Runnable, Future<V>

照例看下类注释

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

-- 一旦任务完成,此任务不能被重新启动(除非任务是通过 {@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.

-- FutureTask 可以被封装成 {@link Callable} 或 {@link Runnable}
Callable 与Runnable 的关系

Executors工具类中有如下代码

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}

/**
 * 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(target, null)

因为FutureTask实现了Runnable接口, 其可以转化为RunnableCallable对象进行操作.

继续看注释

/*
 * 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.
 *
 * Style note: As usual, we bypass overhead of using
 * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
 */
  • 这里说了点与之前版本的不同, 使用了AbstractQueuedSynchronizer来处理中断相关. 通过字段state控制.

又来了!通过AQS控制中断, 之前我们在线程池的Worker中碰到过, 继续往下看FutureTask是怎么玩的~(但源码中并没有看到AQS的使用诶......)

  • 最后一句提到通过直接使用Unsafe内部函数来绕过使用AtomicXFieldUpdaters的开销

AtomicXFieldUpdaters, 通过反射技术来对volatile修饰的X型属性进行原子更新, 很明显这种方式很消耗资源

列一下这几种方式CPU消耗程度,由小到大

  • 基本类型 X: 多线程不安全
  • volatile X: 多线程读取安全,但无法进行原子操作
  • AtomicX: 多线程读安全,可进行原子操作
  • AtomicXFieldUpdate:使用反射,多线程安全和可原子操作

啰嗦了这么多, 到现在终于可以正儿八经地来看下FutureTask这个类的属性了.

字段属性

  • state
/**
 * 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 , 等会一一讲这三个方法.

  • 在任务完成(normal/cancelled/interrupted)之前, FutureTask可能会短暂地存在于COMPLETING (已经设置好返回值) 或 INTERRUPTING(调用cancel(true)方法), 从这些中间状态到最终状态的转换使用更廉价的有序且惰性写入, 因为其值唯一且无法进一步更改.

廉价有序惰性, 意味着占用资源更少, 后文可以看到这一步转换都是使用putOrderedInt方法, 此方法执行时会插入StoreStore内存屏障,避免发生写操作重排序。与之类似的还有putOrderedObject/putOrderedLong, 均属于Unsafe类.

  • 其他属性
/** 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 构造传入, 真正执行的任务
  • outcome 返回结果
  • runner 当前执行线程
  • waiters get方法等待线程列表
/**
 * 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(); }
}

可见这是个单链表, 注释中提到了一个叫做Treiber Stack的东西

Treiber Stack, 简单而言是一个栈, 既然是栈那就有一个非常重要的特性先进后出, 这里也是, 他每次插入都是插入(push)到链头, 而出栈(pop)也是链头先出.详细可参考Treiber Stack

  • 此链表用于记录所有的等待线程.

内部方法

构造方法
/**
 * 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
}

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

两种构造方法, 第一种直接使用Callable方法, 然后返回其返回值.第二种方法将Runnable封装成Callable后执行并返回传入的result.

其他方法
  • 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);
    }
}

这个方法连个方法注释都没有, 真辣鸡~~

  • 需要状态为NEWrunner为空, 然后CAS成功的线程才能成为其runner执行当前任务
  • 第二步中没看懂为啥还要再check一遍state==NEW, 先记着.
  • 然后就是执行call()方法, 拿到返回值result, 这里分两种情况, 一种正常一种异常, 分别执行了set/setException方法, 也是上面唯三的修改state值方法之二, 分别看看.
/**
 * 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();
    }
}
  • 任务成功执行后,CAS修改NEW - COMPLETING, 第一个中间状态来了~
  • 设置返回值, 然后putOrderedInt直接将state 值改成NORMAL
  • 调用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.
 *
 * <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();
    }
}
  • 任务异常执行后,CAS修改NEW - COMPLETING, 第一个中间状态来了~
  • 设置返回值, 然后putOrderedInt直接将state 值改成EXCEPTIONAL
  • 调用finishCompletion()方法

然后都是调用finishCompletion方法

/**
 * 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 (;;) {
                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
}
  • 注释说干了这么几件事: 移除并且唤醒所有等待线程, 调用invoke, callablenull
  • 第一层循环用于找到当前FutureTaskwaiter, 置null
  • 第二层将所有等待线程唤醒
  • 调用done方法, callablenull减少内存占用同时方便GC

done方法是一个protected方法, 默认是空实现, 需要子类自己实现

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

回到run方法的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);
  • runnerstate被设置之前必须为non-null以防止并发调用run方法, 因为run方法的第一步就是一个只有runnernull才能成功的CAS操作.
  • 上面解释了一句, 然后现在任务执行完毕, 可以将runnernull
  • 任务完成后必须重新读取state状态防止遗漏中断(leaked interrupts)

继续看下handlePossibleCancellationInterrupt方法做了啥

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

一个自旋操作, 等待线程退出INTERRUPTING状态

说到现在, waiters这个链表好像没有用到诶~

接下来重点看下get()方法

/**
 * @throws CancellationException {@inheritDoc}
 */
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}

当小于等于COMPLETING 时,调用awaitDone方法.

前面我们在run方法中有两个状态转换:

NEW -> COMPLETING -> NORMAL
NEW -> COMPLETING -> EXCEPTIONAL

COMPLETING这个状态只在这里出现过, 那就是当FutureTask还没执行结束时, 执行awaitDone

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

类注释写了这个方法四种结果

  • 等待执行完成
  • 取消
  • 中断
  • 超时

处理逻辑

  • 如果线程已经中断, 移除waiter, 抛出InterruptedException
  • 如果线程已经完成, 置空线程位, 返回状态位
  • 如果COMPLETING中, 则短暂yield释放一下
  • 然后就是将当前线程构建成WaitNode一直往waiters链表头部(自旋 + CAS, 还记得前面说的Treiber Stack吗?)
  • 加入链表成功后, 挂起(分是否需要超时设置不同处理)

然后就是report方法

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

这个方法就很简单粗暴了, 正常结束就正常返回, 否则抛出对应异常.

还有几个状态目前我们没接触到, 就是异常与取消

NEW -> CANCELLED
NEW -> INTERRUPTING -> INTERRUPTED

来看看什么时候会用到他们

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;
}
  • mayInterruptIfRunningfalse, 则状态改为CANCELLED
  • mayInterruptIfRunningtrue, 则状态改为INTERRUPTING, 然后中断其线程, 最后状态改为INTERRUPTED
  • 最后都执行finishCompletion方法.

最后我们看下FutureTask中的最后一个方法runAndReset

/**
 * 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方法非常类似, 下面提几点不同

  • 从方法名就看得出来, runAndReset不会设置返回值
  • runAndReset方法有返回值, 如果执行成功且没有被中断或取消返回true, 否则返回false

最后来讲讲 CAS 到底是个啥.

FutureTask为例来看下.

CAS操作就是 compareAndSwap, 比较然后交换, 但在多线程下这种操作是问题的, 所以只能从硬件层面上实现, 只要比较成功那么一定交换成功, 也就是说这是一个原子操作.

那么此方法需要什么呢?

看下源码

CAS操作都是通过 UnSafe类来实现, 从名字就知道这个类可以做很多坏事~ 慎用

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
  • var1 操作对象
  • var2 对象字段在对象中的偏移量
  • var4 期望值
  • var5 修改值

简而言之, 当对象字段的值为期望值时, 更新为修改值

可能就这个偏移量var2不知道咋玩.

看下FutureTask 中的用法

// 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);
    }
}
  • getDeclaredField 通过反射拿到字段对象 Field
  • objectFieldOffset UnSafe的方法, 通过Field对象拿到其所在偏移量

每个使用CAS的类, 就看他这一步拿了哪些字段的偏移量, 就表示需要使用CAS操作哪些字段. 比如这里只用到了state/runner/waiters


这篇博客前后写了快一周, 不是细嚼慢咽, 也不是FutureTask源码有多难啃, 纯粹是琐事太多与性子懒劲上来了.....

珍惜能静下心来学习的日子。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343