JAVA FutureTask之AbstractQueuedSynchronizer 源码分析

在java.util.concurrent.locks包中有很多Lock的实现类,ReentrantLock,CountDownLatch,FutureTask,ReentrantReadWriteLock,Semaphore
每个实现类都有不同的使用场景,,,这篇文章介绍FutureTask的源码实现
这里会涉及到 独占锁和共享锁的概念。
 
独占锁:同一时间只有一个线程获取锁。再有线程尝试加锁,将失败。 典型例子 reentrantLock
共享锁:同一时间可以有多个线程获取锁。 典型例子,本例中的FutureTask

AbstractQueuedSynchronizer的实现非常精妙,看一次两次也许还不能真正领悟到它的精髓,,,,所以,,有时间不停的琢磨阅读,不停的深入,,才能了解到作者的精髓。。。


写这篇文章之前看了很多帖子,有些写的还不错,比如 

http://liuinsect.iteye.com/blog/1994831

http://blog.youkuaiyun.com/chen77716/article/details/6641477

但是,看了这些文章还是不能真正理解AQS如何工作,,,比如AbstractQueuedSynchronizer.Node的状态的变化,如何协调线程资源的竞争等等。

光看代码有点难以理解,,,得借助debug工具,才能帮助更容易理解。要让AbstractQueuedSynchronizer可调试,也是件比较麻烦的事情,我花了将近1天的时间才搞定,看这篇帖子   http://blog.youkuaiyun.com/u013603157/article/details/18960217


我们模拟 一个场景,一个线程执行FutureTask的run方法,多个线程调用FutureTask的get方法,假设run方法执行比较慢,,,所有的get方法都要阻塞,,,等run方法执行完后再一个个唤醒所有阻塞


futureTask的get方法调用

 V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
            if (!tryAcquireSharedNanos(0, nanosTimeout))
                throw new TimeoutException();
            if (getState() == CANCELLED)
                throw new CancellationException();
            if (exception != null)
                throw new ExecutionException(exception);
            return result;
        }

调用
private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
        throws InterruptedException {

        long lastTime = System.nanoTime();
        final Node node = addWaiter(Node.SHARED);//将当前的线程组装成Node,插入
        //到队列的尾部,并且返回新生成的node
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {//当队列里面只有一个node的时候(队列头初始node
                //不算)满足 p == head
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {//认为已经完成(任务状态为(RAN | CANCELLED)
                    //&& runner == null)
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return true;
                    }
                }
                if (nanosTimeout <= 0)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                long now = System.nanoTime();
                nanosTimeout -= now - lastTime;
                lastTime = now;
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    
    在39行 LockSupport.parkNanos;(this, nanosTimeout);的本地方法,将线程阻塞,,
    //这个时候该线程创建的Node对象的state为什么状态呢?
    答案在shouldParkAfterFailedAcquire 方法
     private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {//新生成的Node的waitStatus状态默认为0,,通过以下的原子操作,状态修改为SIGNAL,然后方法结束后,又会执行一次循环,
        //走到第54行位置if (ws == Node.SIGNAL),返回true后,将线程阻塞。为什么要这么做呢??目前还没打看明白,待续。。。
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }
    
    回到我们模拟的场景,多个调用get方法的线程都在37行的位置阻塞住了,,,,现在FutureTask的run方法运行完了,,,
    void innerRun() {
            if (!compareAndSetState(READY, RUNNING))
                return;

            runner = Thread.currentThread();
            if (getState() == RUNNING) { // recheck after setting thread
                V result;
                try {
                    result = callable.call();
                } catch (Throwable ex) {
                    setException(ex);
                    return;
                }
                set(result);
            } else {
                releaseShared(0); // cancel
            }
        }
    假如没有抛出任何异常(为了模拟主干流程,各种分支异常先忽略掉),调用set(result)方法,修改任务状态,并释放阻塞的线程。
    protected void set(V v) {
        sync.innerSet(v);
    }
    
    void innerSet(V v) {
            for (;;) {
                int s = getState();
                if (s == RAN)
                    return;
                if (s == CANCELLED) {
                    // aggressively release to set runner to null,
                    // in case we are racing with a cancel request
                    // that will try to interrupt runner
                    releaseShared(0);
                    return;
                }
                if (compareAndSetState(s, RAN)) {
                    result = v;
                    releaseShared(0);
                    done();
                    return;
                }
            }
        }
        
        关键是releaseShared(0); 方法释放了所有等待的线程
        public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
    
    tryReleaseShared 一定会返回true,主要看doReleaseShared();
    private void doReleaseShared() {
        /*
         * Ensure that a release propagates, even if there are other
         * in-progress acquires/releases.  This proceeds in the usual
         * way of trying to unparkSuccessor of head if it needs
         * signal. But if it does not, status is set to PROPAGATE to
         * ensure that upon release, propagation continues.
         * Additionally, we must loop in case a new node is added
         * while we are doing this. Also, unlike other uses of
         * unparkSuccessor, we need to know if CAS to reset status
         * fails, if so rechecking.
         */
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }
    
    回到39行,线程调用get的时候,将本线程的Note的waitStatus状态设置为SIGNAL,所以156行的
     if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
    将head所指向的Node的waitStatus设置为0,并唤醒head所指向Node的线程,,,然后
    doAcquireSharedNanos的LockSupport.parkNanos(this, nanosTimeout);醒了,,代码继续往下走,,,,
    在下一轮的循环中,通过setHeadAndPropagate  释放内存,并且唤醒所有阻塞的线程
    private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // Record old head for check below
        setHead(node);//修改新的head引用,同时释放内存,避免内存泄漏
        /*
         * Try to signal next queued node if:
         *   Propagation was indicated by caller,
         *     or was recorded (as h.waitStatus) by a previous operation
         *     (note: this uses sign-check of waitStatus because
         *      PROPAGATE status may transition to SIGNAL.)
         * and
         *   The next node is waiting in shared mode,
         *     or we don't know, because it appears null
         *
         * The conservatism in both of these checks may cause
         * unnecessary wake-ups, but only when there are multiple
         * racing acquires/releases, so most need signals now or soon
         * anyway.
         */
        if (propagate > 0 || h == null || h.waitStatus < 0) {
            Node s = node.next;//s指向下一个Node的引用
            if (s == null || s.isShared())
                doReleaseShared();//唤醒下一个线程。就像多米诺骨牌效应。
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值