从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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FutureTask是Java中Executor框架提供的一个实用工具类,用来表示一个异步计算的结果,其中包含了对任务的执行状态以及返回结果的控制。FutureTask实现原理主要包括以下几个方面: 1. FutureTask内部有一个volatile修饰的state字段,用于表示任务的执行状态。初始状态为NEW,表示任务还未开始执行;运行状态为RUNNING,表示任务正在执行中;完成状态为COMPLETING,表示任务已经执行完成但还未获取结果;NORMAL,表示任务正常执行完成;异常状态为EXCEPTIONAL,表示任务执行过程中发生异常。 2. FutureTask实现了Runnable和Future接口。在任务执行的过程中,通过重写Runnable接口的run方法来执行具体的任务逻辑,并将任务的结果保存在result字段中。因为实现了Future接口,所以FutureTask可以通过get方法来获取任务的执行结果,如果任务还未执行完成,则get方法会阻塞等待任务完成。 3. FutureTask使用AQS(AbstractQueuedSynchronizer)来实现任务的执行控制。AQS是Java并发包中用于实现锁和同步器的基础类,通过实现AQS的子类Sync,来控制任务的执行和获取结果的过程。在任务执行过程中,通过CAS操作来更新任务的执行状态,确保只有一个线程能够成功获取任务的结果。 4. FutureTask还支持任务的取消操作。在调用cancel方法时,会尝试将任务的执行状态设置为CANCELLED,如果设置成功,则任务会被标记为已取消。取消任务时,如果任务已经在执行过程中,则会中断该任务的执行线程。 总之,FutureTask通过内部的状态管理、AQS实现控制、Runnable和Future接口的实现,实现了异步任务的执行控制和结果获取功能,为多线程编程提供了更强大和便捷的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值