同步輔助類:
CountDownLatch是一個同步輔助類,在jdk5中引入,它允許一個或多個線程等待其他線程操作完成之后才執行。
實現原理 :
CountDownLatch是通過計數器的方式來實現,計數器的初始值為線程的數量。每當一個線程完成了自己的任務之后,就會對計數器減1,當計數器的值為0時,表示所有線程完成了任務,此時等待在閉鎖上的線程才繼續執行,從而達到等待其他線程完成任務之后才繼續執行的目的。
CountDownLatch主要方法:
CountDownLatch具體是通過同步器來實現的,使用AQS狀態來表示計數:
/** * 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;
1、構造函數
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
通過傳入一個數值來創建一個CountDownLatch,數值表示線程可以從等待狀態恢復,countDown方法必須被調用的次數
2、countDown方法
public void countDown() { sync.releaseShared(1); }
線程調用此方法對count進行減1。當count本來就為0,此方法不做任何操作,當count比0大,調用此方法進行減1,當new count為0,釋放所有等待當線程。
3、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