一個同步輔助類,在完成一組正在其餘線程中執行的操做以前,它容許一個或多個線程一直等待。用給定的計數 初始化 CountDownLatch。因爲調用了 countDown() 方法,因此在當前計數到達零以前,await 方法會一直受阻塞。以後,會釋放全部等待的線程,await 的全部後續調用都將當即返回。這種現象只出現一次——計數沒法被重置。源碼分析
在一些應用場合中,須要等待某個條件達到要求後才能作後面的事情。
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
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
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
建立CountDownLatch對象時,須要傳入一個int的計數器。對象
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(); }
獲取計數器當前值。