CountDownLatch 源碼分析

1. 類介紹

一個同步輔助類,在完成一組正在其餘線程中執行的操做以前,它容許一個或多個線程一直等待。用給定的計數 初始化 CountDownLatch。因爲調用了 countDown() 方法,因此在當前計數到達零以前,await 方法會一直受阻塞。以後,會釋放全部等待的線程,await 的全部後續調用都將當即返回。這種現象只出現一次——計數沒法被重置。源碼分析

2. 使用場景

在一些應用場合中,須要等待某個條件達到要求後才能作後面的事情。
CountDownLatch最重要的方法是countDown()和await()兩個方法,countDown主要是倒數一次,await是等待倒數到0,若是沒有到達0,就只有阻塞等待了。
例如:
A 和 B 相約一塊兒吃飯,等A和B都到指定頂點後才能開始吃飯,下面用代碼模擬實現。ui

示例

public class CountDownLatchTest {
    static CountDownLatch c = new CountDownLatch(2);
    
    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                System.out.println("A 我來了");
                c.countDown();
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                System.out.println("B 我來了");
                c.countDown();
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                try {
                    c.await();
                    System.out.println("開始吃飯...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
}

源碼分析:

須要提早了解:AbstractQueuedSynchronizer 源碼分析this

AQS提供了兩種模式:獨佔模式&共享模式。CountDownLatch就是一個使用共享模式的自定義同步器實現的共享鎖。spa

CountDownLatch 代碼很少,主要是經過內部類繼承AQS來實現其功能的,下面咱們一步一步來分析下源碼:.net

Sync 內部類

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

    //構造Sync對象是初始化AQS中state的數量(共享鎖的個數)
    Sync(int count) {
        setState(count);
    }

    //獲取當前state的數量(共享鎖個數)
    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;
        }
    }
}

AbstractQueuedSynchronizer 類採用模版模式進行擴展實現其相應的功能。子類只須要實現
以下5個方法就能實現其不一樣功能的鎖。線程

而CountDownLatch 的內部類Sync使用的是共享鎖因此只實現了tryAcquireShared和tryReleaseShared方法。code

CountDownLatch的構造方法

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

建立CountDownLatch對象時,須要傳入一個int的計數器。對象

await 方法

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

public boolean await(long timeout, TimeUnit unit)
    throws InterruptedException {
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

await方法調用AQS的得到鎖的方法,只有AQS的state狀態爲0時才能得到鎖,若是state不爲0,則須要在AQS的等待隊列中阻塞等待。blog

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

countDown方法則調用AQS的releaseShared方法,釋放共享鎖,也就是每次將state狀態每次減一,直到減到0,則喚醒隊列中的全部節點(線程)。繼承

public long getCount() {
    return sync.getCount();
}

獲取計數器當前值。

相關文章
相關標籤/搜索