同步輔助類:java
CountDownLatch是一個同步輔助類,在jdk5中引入,它容許一個或多個線程等待其餘線程操做完成以後才執行。 git
實現原理 :github
CountDownLatch是經過計數器的方式來實現,計數器的初始值爲線程的數量。每當一個線程完成了本身的任務以後,就會對計數器減1,當計數器的值爲0時,表示全部線程完成了任務,此時等待在閉鎖上的線程才繼續執行,從而達到等待其餘線程完成任務以後才繼續執行的目的。函數
CountDownLatch主要方法:ui
CountDownLatch具體是經過同步器來實現的,使用AQS狀態來表示計數:this
/** * Synchronization control For CountDownLatch. * Uses AQS state to represent count. */ 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; } } } private final Sync sync;
一、構造函數 spa
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
經過傳入一個數值來建立一個CountDownLatch,數值表示線程能夠從等待狀態恢復,countDown方法必須被調用的次數線程
二、countDown方法code
public void countDown() { sync.releaseShared(1); }
線程調用此方法對count進行減1。當count原本就爲0,此方法不作任何操做,當count比0大,調用此方法進行減1,當new count爲0,釋放全部等待當線程。blog
三、await方法
(1)不帶參數
public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); }
調用此方法時,當count爲0,直接返回true,當count比0大,線程會一直等待,直到count的值變爲0,或者線程被中斷(interepted,此時會拋出中斷異常)。
(2)帶參數
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); }
調用此方法時,當count爲0,直接返回true,當count比0大,線程會等待一段時間,等待時間內若是count的值變爲0,返回true;當超出等待時間,返回false;或者等待時間內線程被中斷,此時會拋出中斷異常。
CountDownLatch實踐
司機和工人,工人必須等到司機來了才能裝貨上車,司機必須得等到全部工人把貨物裝上車了以後才能把車開走。
工人類:
public class Worker implements Runnable { private String workerCode; private CountDownLatch startLatch; private CountDownLatch latch; Worker(CountDownLatch startLatch, CountDownLatch latch, String workerCode) { this.startLatch = startLatch; this.latch = latch; this.workerCode = workerCode; } public void run() { try { startLatch.await(); doWork(); latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } private void doWork() { System.out.println("Worker " + workerCode + " is loading goods..."); } }
司機類:
public class Driver { public static void main(String[] args) throws InterruptedException { CountDownLatch startLatch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(10); ExecutorService executor = Executors.newFixedThreadPool(10); for(int i=0; i<10; i++) { executor.execute(new Worker(startLatch, latch, "worker" + i)); } System.out.println("Driver is here."); startLatch.countDown(); System.out.println("Workers get to work."); latch.await(); System.out.println("Driver is ready to go."); executor.shutdown(); } }
運行結果:
Driver is here.
Workers get to work.
Worker worker0 is loading goods...
Worker worker1 is loading goods...
Worker worker2 is loading goods...
Worker worker3 is loading goods...
Worker worker4 is loading goods...
Worker worker5 is loading goods...
Worker worker7 is loading goods...
Worker worker9 is loading goods...
Worker worker8 is loading goods...
Worker worker6 is loading goods...
Driver is ready to go.
完整工程代碼請參考git:https://github.com/xuweijian/CountDownLatch.git