標籤:closed ace exception run hid 執行 rup 控制 protected
簡介:
CountDownLatch 是一個非常實用的多線程式控制制工具類,通常用來控制線程的等待,它可以讓某個線程等待直到倒計時結束
CountDownLatch 提供了兩個主要的方法,await()、countDown()。
執行個體:
public class CountDownLatchDemo implements Runnable { static final CountDownLatch end = new CountDownLatch(10); static final CountDownLatchDemo demo = new CountDownLatchDemo(); @Override public void run() { try { Thread.sleep(new Random().nextInt(10) * 1000); System.out.println("check complete..."); end.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) throws InterruptedException { ExecutorService exec = Executors.newFixedThreadPool(10); for (int i = 0;i < 10;i++) { exec.submit(demo); } end.await(); System.out.println("Fire!"); exec.shutdown(); }}原理解析:
countDownLatch 的計數是通過一個共用變數(volatile)實現的,下面分析它的三個核心函數:建構函式,CountDownLatch(int count);阻塞線程,await();計數器減一,countDown()。
CountDownLatch(int count)
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count);}
其中 Sync 是 CountDownLatch 的內部類,並且 Sync 繼承了 AbstractQueuedSynchronizer
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; } }}View Code
其中 setState 是設定 AbstractQueuedSynchronizer 中 state 變數,該變數聲明了 volatile。
State 就是 countDownLatch 中的計數器。
await()
public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1);}public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquireShared(arg) >= 0 || doAcquireSharedNanos(arg, nanosTimeout);}
acquireSharedInterruptibly() 的作用是擷取共用鎖定,如果當前線程處於中斷狀態,則拋出 InterruptedException,否則,調用 tryAcquireShared(arg) 嘗試擷取共用鎖定,如果鎖計數器 = 0,則表示鎖為可擷取狀態,返回 1,否則,鎖為不可擷取狀態,則返回 -1。
doAcquireSharedNanos() 會使當前線程一直等待,直到當前線程擷取到共用鎖定(或線程被中斷)才返回。
countDown()
public void countDown() { sync.releaseShared(1);}public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { doReleaseShared(); return true; } return false;}
releaseShared() 目的是讓當前線程釋放它所持有的共用鎖定。
tryReleaseShared() 的作用是釋放共用鎖定,將鎖計數器的值減一。
總結
CountDownLatch 是通過共用鎖定實現的。CountDownLatch 建構函式傳遞 int 參數,該參數是計數器的初始狀態,表示共用鎖定最多能被 count 個線程同時擷取。
當某線程調用 CountDownLatch 的 await 方法時,該線程會等待共用鎖定可用時(計數器為 0 時),才能擷取共用鎖定,進而繼續執行。
每次執行 countDown 時,會將計數器減一。
參考資料
Java多線程系列--“JUC鎖”09之 CountDownLatch原理和樣本
Java多線程系列——計數器 CountDownLatch