CountDownLatch源码解析

1. 首先看一下CountDownLatch的构造函数

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

然后看一下Sync类,是一个静态内部类,继承了AQS,重写了tryAcquireShared()tryReleaseShared()两个共享的方法

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

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        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;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

构造对象时,传入state初始值

2. 看一下countDown()方法

		public void countDown() {
        	sync.releaseShared(1);
    	}

countDown时会把state-1,看一下releaseShared()方法的实现

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

tryReleaseShared()为内部类实现,如果state = state-1设置成功,并且state为0时返回true,为true时调用了doReleaseShared()方法。介绍完await()方法再介绍此方法

3. 看一下await()方法

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

await方法中获取1个状态,最终调用内部类实现的tryAcquireShared()方法,此方法只有在state==0时才返回1,否则返回-1(返回-1表示state>0,也就是计数没有用完),调用doAcquireSharedInterruptibly()方法,看一下此方法

	private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            throw t;
        }
    }

addWaiter()方法表示增加一个新Node节点到等待队列尾部,并返回这个新节点。当执行到tryAcquireShared()方法时,若state!=0,返回-1,后面会进入parkAndCheckInterrupt()方法等待

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

4. 下面看一下doReleaseShared()方法

    private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

看一下unparkSuccessor()方法

    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            node.compareAndSetWaitStatus(ws, 0);

        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node p = tail; p != node && p != null; p = p.prev)
                if (p.waitStatus <= 0)
                    s = p;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

unparkSuccessor()方法会唤醒等待的线程,正好唤醒上面await()方法park的线程

5. 总结

利用AQS的state表示计数值,每次调用countDown()方法时会减一,当减到0时会唤醒await()方法等待的线程。

实时内容请关注微信公众号,公众号与博客同时更新:程序员星星
在这里插入图片描述

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页