FutureTask源码分析

83 阅读6分钟

FutureTask为什么能在线程池中使用

image.png

FutureTask实现了RunnableFuture接口,所以可以被当成一个Runnable执行

再看submit方法

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

传入的是一个Callable,在newTaskFor中完成了封装为RunnableFuture

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable; //传入的callable
    this.state = NEW;       // 设置状态
}

这里运用了设计模式中的装饰者模式,Callable最终被封装成RunnableFuture,这样就可以交给execute()处理了。

FutureTask的结构

public class FutureTask<V> implements RunnableFuture<V> {
    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; //当前的callable

    private Object outcome; //返回值,get()的返回结果或异常

    private volatile Thread runner; //运行callable的线程

    //当有多个线程调用 `get` 方法等待任务执行完成时,它们会被加入到 `waiters` 链表中。
    private volatile WaitNode waiters;  //使用Treiber栈保存等待线程

  • NEW:表示是个新的任务或者还没被执行完的任务。这是初始状态。

  • COMPLETING:任务已经执行完成或者执行任务的时候发生异常,但是任务执行结果或者异常原因还没有保存到outcome字段(outcome字段用来保存任务执行结果,如果发生异常,则用来保存异常原因)的时候,状态会从NEW变更到COMPLETING。但是这个状态会时间会比较短,属于中间状态。

  • NORMAL:任务已经执行完成并且任务执行结果已经保存到outcome字段,状态会从COMPLETING转换到NORMAL。这是一个最终态。

  • EXCEPTIONAL:任务执行发生异常并且异常原因已经保存到outcome字段中后,状态会从COMPLETING转换到EXCEPTIONAL。这是一个最终态。

  • CANCELLED:任务还没开始执行或者已经开始执行但是还没有执行完成的时候,用户调用了cancel(false)方法取消任务且不中断任务执行线程,这个时候状态会从NEW转化为CANCELLED状态。这是一个最终态。

  • INTERRUPTING: 任务还没开始执行或者已经执行但是还没有执行完成的时候,用户调用了cancel(true)方法取消任务并且要中断任务执行线程但是还没有中断任务执行线程之前,状态会从NEW转化为INTERRUPTING。这是一个中间状态。

  • INTERRUPTED:调用interrupt()中断任务执行线程之后状态会从INTERRUPTING转换到INTERRUPTED。这是一个最终态。 有一点需要注意的是,所有值大于COMPLETING的状态都表示任务已经执行完成(任务正常执行完成,任务执行异常或者任务被取消)。

入口run()

public void run() {
    if (state != NEW || //状态不是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();//调用可调用对象的call方法,result为调用结果
                ran = true; //调用成功标识
            } catch (Throwable ex) {
                result = null;
                ran = false; //失败标识
                setException(ex); //这里会将状态从NEW修改为COMPLETING并记录异常到outcome中,后续看
            }
            if (ran)
                set(result);//如果调用成功 设置result,这里内部也会涉及outcome和状态改变
        }
    } 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); //中断处理
    }
}

set()

protected void set(V v) {
    //修改状态为完成,注意此状态表示还为设置outcome
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;//保存结果到outcome
        //设置为normal,这是一个最终态,表示outcome已经设置
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

finishCompletion()

private void finishCompletion() {
    // 循环处理等待节点
    for (WaitNode q; (q = waiters) != null;) {
        // 使用 CAS 置空 waiters 字段,成功则进入处理等待节点的循环
        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; // 为了减小内存占用,将 callable 字段置空
}

setException()

和set方法类似,只是状态变成EXECPTIONAL,outcome存储的是异常信息

protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion();
    }
}

中断处理

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

获取返回值get()

public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING) //如果是还没有设置返回值的状态
        s = awaitDone(false, 0L); //没设置超时时间的等待
    return report(s);
}

//有参,超时时间和单位
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);
}

awaitDone()

private int awaitDone(boolean timed, long nanos) throws InterruptedException {
    // 计算超时的截止时间
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    // 表示当前线程的等待节点
    WaitNode q = null;
    // 是否已经加入等待队列
    boolean queued = false;

    for (;;) {
        // 如果线程被中断,移除等待节点并抛出 InterruptedException
        if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }

        // 获取当前任务的状态
        int s = state;
        // 如果任务已经完成,返回任务的状态
        // 第一次自旋
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null; // 将等待节点的线程字段设置为 null
            return s;
        }
        // 如果任务正在完成中,暂时不能超时,进行 Thread.yield() 让出 CPU
        // 第二次自旋
        else if (s == COMPLETING)
            Thread.yield();
        // 如果没有等待节点,创建一个新的 WaitNode
        else if (q == null)
            q = new WaitNode();
        // 如果还没有加入等待队列,并且成功使用 compareAndSwapObject 将当前等待节点插入等待队列
        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 进行带有超时的等待
            LockSupport.parkNanos(this, nanos);
        }
        // 如果没有设置超时时间,使用 LockSupport.park 进行无限期等待
        else
            LockSupport.park(this);
    } 
}

等待节点是怎么被唤醒的,见finishCompletion()方法

reports() —— 返回get()结果

private V report(int s) throws ExecutionException {
    Object x = outcome; //拿到outcome
    if (s == NORMAL)
        return (V)x;    //返回结果
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

cancel()

public boolean cancel(boolean mayInterruptIfRunning) {
    // 检查任务是否仍处于 NEW 状态,并转换为 INTERRUPTING(如果请求中断)
    // 或 CANCELLED(如果未请求中断)。
    if (!(state == NEW &&
          UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
              mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;

    try {
        // 如果请求中断
        if (mayInterruptIfRunning) {
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();
            } finally { // 最终状态
                // 将状态过渡到 INTERRUPTED,表示线程已被中断
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        // 唤醒等待队列上的线程(也就是还在get()阻塞的)
        finishCompletion();
    }

    return true; // 任务取消成功
}