CountDownLatch 源码解析

179 阅读2分钟

CountDownLatch

内部类Sync 继承自AQS

 private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        //初始化时用AQS的state做计数器
        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        //只是判断了一下state是否为0
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        //tryReleaseShared cas 把state-1 当state为0时返回true,否则返回false
        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                //如果当前tryReleaseShared把state变成0返回true,否则返回false
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
        
    public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            //当state!=0是执行doAcquireShared把线程加入到队列中
            doAcquireShared(arg);
    }

countDown方法

    public void countDown() {
        sync.releaseShared(1);
    }
    
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            //如果释放得到0,才执行doReleaseShared方法
            //逐渐释放队列中的所有值
            doReleaseShared();
            return true;
        }
        return false;
    }

await方法

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        //响应中断
        if (Thread.interrupted())
            throw new InterruptedException();
        //如果state不为0,doAcquireSharedInterruptibly把当前线程加入到阻塞队列中并阻塞 如果为0则不阻塞
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
    
    //初始waitstatus状态为0,更新成-1后阻塞线程
    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 {
            /*
             * 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;
    }

总结

1.CountDownLatch内部有一个Sync继承自AQS,使用AQS的state属性作为计数器。 2.await方法调用tryAcquireShared,tryAcquireShared不会对AQS的属性做变更,只会返回state的属性是否大于0,如果不为0说明不能执行,加入到AQS的阻塞队列中,在队列中的线程会自旋执行tryAcquireShared,即判断是否为0,如果不是0则阻塞。 3.countDown()方法每次通过cas吧state减1,如果结果为0,唤醒队列中所有的线程