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()方法等待的線程。

實時內容請關注微信公衆號,公衆號與博客同時更新:程序員星星
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章