从FutureTask内部类WaitNode深入浅出分析FutureTask实现原理

最近在看并发包的源码把自己的理解分享给大家啦,有不正确的地方欢迎大家指正。 FutureTask类中的waiters成员变量保存着调用get方法获取FutureTask计算结果的线程构成的一个栈。 当FutureTask类run方法没有执行完时,调用get方法的线程会形成一个阻塞的栈,即waiters。

static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
  }

一旦FutureTask类run方法执行完、执行中出现异常或者是调用cancel方法取消执行(可以通知正在执行 FutureTask类run方法的线程响应中断,通过设置cancel方法参数mayInterruptIfRunning为true达到) 时,就必须让阻塞在waiters栈的所有线程退出阻塞。这个是通过FutureTask类的finishCompletion方法 完成的。源码如下:

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
}

所以,在FutureTask类run方法中的执行完成员变量的callable的call方法时,正常执行或是执行出现异常 调用set设置执行后的结果或是setException设置执行返回出现的异常时,其内部都调用finishCompletion 方法,同理cancel方法内部也调用了finishCompletion方法。FutureTask类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;
                /*执行callable的call方法出现异常,设置异常,setException内部调用
                   finishCompletion让阻塞在waiters栈上的所有要获取run方法执行结
                   果的线程全部停止阻塞,得到执行时的异常
                */
                setException(ex);
            }
            if (ran)
                /*正常执行完callable的call方法,设置返回结果,set内部调用finishCompletion
                   让阻塞在waiters栈上的所有要获取run方法执行结果的线程全部停止阻塞得到
                   执行的结果
                */
                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);
    }
}

现在反过来分析一下,waiters栈是如何构成的。先看一下FutureTask类get方法,就是得到Callable 的执行结果,我们前说的所有要获取run方法执行结果的线程,就是调用 get方法。源码如下:

public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        /*FutureTask类run方法执行callable的call方法没完成,要获取run方法执行结果的线程阻塞构成
           waiters栈
        */
        s = awaitDone(false, 0L);
    return report(s);
}

FutureTask类有个get变体用于在指定时间没有获取结果抛出异常,同get类似这里不做分析,来看下 awaitDone源码:

/**
* Awaits completion or aborts on interrupt or timeout.
*
* [@param](https://my.oschina.net/u/2303379) timed true if use timed waits
* [@param](https://my.oschina.net/u/2303379) nanos time to wait, if timed
* [@return](https://my.oschina.net/u/556800) 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 (;;) {
        //调用get的线程被中断,将其对应waiterNode移除,同时抛出异常,interrupted会重置中断状态
        if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }
        int s = state;
        //FutureTask中run方法执行,即callable任务执行完,返回执行的状态
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;
            return s;
        }
        //FutureTask执行处于中间状态,获取结果的线程将cup执行机会让给真正要执行FutureTask类run方法的线程
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();
        else if (q == null)
        //将要获取结果的线程封装成对应的WaitNode,用于后面构建阻塞waiters栈
            q = new WaitNode();
        else if (!queued)
            //构建阻塞waiters栈
            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
            //阻塞当前获取FutureTask类执行结果的线程
            LockSupport.park(this);
    }
}

上面注解已详细分析了awaitDone方法。有问题欢迎指正。

转载于:https://my.oschina.net/u/1421030/blog/1546531

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值