Multithreading foundation (thirteen): FutureTask in java

Get into the habit of writing together! This is the 13th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the event details .

@[toc] FutureTask source code analysis

1. Class structure and constants and variables

1.1 Class structure

The FutureTask class structure is as follows:

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

    
}
复制代码

As you can see, FutureTask implements the RunnableFuture interface, and the RunnableFuture interface inherits Future and Runnable. As shown below:image.png

The above comments are to the effect: Future is a cancelable asynchronous computing framework that provides a basic implementation of the Future interface, including start, cancel, and query to check whether the calculation is completed and methods to retrieve the calculation results. The result can only be retrieved after the calculation is complete, if the calculation has not been completed, the get method will block, and once the calculation is complete, the calculation cannot be restarted or canceled. Unless runAndReset is used. FutureTask can be used to wrap Callable or Runnable objects. Since FutureTask implements the Runnable interface, FutureTask can be submitted to Executor for execution. In addition to being used alone, this class also provides protected methods that support extensions, which may be useful when creating custom tasks.

There are also revision notes: This is different from earlier versions that relied on the AbstractQueuedSynchronizer implementation. This class is mainly to avoid the user to keep the interrupted state during the cancellation of the task. The synchronization control in the current design relies on the status field updated through the cas to track the completion. , and a simple Treiber stack to hold waiting threads. Style Notes: As always, we bypassed the overhead of using AtomicXFieldUpdaters. And directly use the internal functions of UnSafe.

1.2 Constants

/**
 * 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 according to the incoming time, if the time is 0, wait indefinitely.

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);
    }
}
复制代码

It can be seen that the FutureTask uses LockSupport.park to block the thread submitting the task and make it enter the WAIT state.

3.4 cancel

This method will cancel the 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

After execution, delete and notify all waiting threads.

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

Try to unlink a timeout or interrupted waiting node to avoid accumulating garbage. Internal nodes are not spliced ​​together without cas, because it is harmless if the releaser traverses them anyway. To avoid the effect of unsplitting from a deleted node, the list will be re-traversed in the event of significant contention. When there are many nodes, it will cause very slow.

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

This method is the main method of executing FruitTask.

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

Execute the calculation without setting the result of the calculation, then reset this state to the initial state, and fail if an exception and cancel are encountered. It is designed for tasks that are inherently performed multiple times.

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;
}
复制代码

This method cleans up the state after each execution, resets it to new, and is designed to be executed repeatedly.

4. Inner class WaitNode

WaitNode is a linked list node that records waiting threads.

/**
 * 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. Summary

FutureTask is not complicated. It implements the Future design pattern. In fact, the essence is to do an asynchronous process, but it will make the submitter of the task enter the waiting process until the task is executed. Then get the result of execution.

Guess you like

Origin juejin.im/post/7086412593929125918