CyclicBarrier、CountDownLatch以及Semaphore使用及其原理分析

IT技術精選文摘發表於2018-06-24

640?wx_fmt=gif

CyclicBarrier、CountDownLatch以及Semaphore是Java併發包中幾個常用的併發元件,這幾個元件特點是功能相識很容易混淆。首先我們分別介紹這幾個元件的功能然後再通過例項分析和原始碼分析其中設計原理。

CyclicBarrier

主要功能:

CyclicBarrier的主要功能是使1~(N-1)個執行緒達到某個屏障後阻塞,直到第N個執行緒到達該屏障後才會被開啟,這是所有的執行緒才能繼續執行下去,CyclicBarrier同時支援一個Runable物件,當所有執行緒到達該屏障時執行該Runable物件。

用例:

640?wx_fmt=png

輸出:

Thread-0達到屏障
Thread-2達到屏障
Thread-1達到屏障
Thread-1離開屏障
Thread-2離開屏障
Thread-0離開屏障

可以看到三個執行緒同時達到屏障後所有執行緒才開始離開屏障繼續執行。下面我們將分析其設計原理。

設計原理

CyclicBarrier呼叫await()方法是執行緒等待,await()方法原始碼如下:

640?wx_fmt=png

其內部呼叫的是doWait()方法,await()還有一個帶超時的過載方法,功能類似。doWait()方法程式碼如下:

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

Generation是一個靜態內部類,表明CyclicBarrier的代,表明每個CyclicBarrier執行的例項,如果當前CyclicBarrier正常執行完將會重置代,否則將會破壞代。

640?wx_fmt=png

breakBarrier方法會破壞屏障,可以看到起設定了代為破壞狀態同時呼叫Condition的signalAll方法喚醒所有在等待的執行緒。

640?wx_fmt=png

nextGeneration主要作用為重置下一代,內部也會喚醒正在等待的執行緒同時將屏障數量復位方便下一次使用。

CountDownLatch

CountDownLatch的主要功能是實現幾個計數器,使N個現場執行完成後當前執行緒才會繼續執行下去。比如我們希望將一個事件分成多個執行緒去執行,執行完後進行彙總這種情景就可以使用CountDownLatch。

用例

640?wx_fmt=png

輸出:

Thread-0執行完畢
Thread-1執行完畢
Thread-2執行完畢
Thread-3執行完畢
Thread-4執行完畢
主執行緒執行

原理分析

構造方法

640?wx_fmt=png

CountDownLatch建構函式中呼叫了Sync構造方法,Sync繼承了AQS內容如下:

640?wx_fmt=png

設定了state,這個東西再熟悉不過了,在可重入鎖中表示是否獲取到鎖的標誌位。

我們首先看await方法,

640?wx_fmt=png

實際呼叫的是AQS的acquireSharedInterruptibly方法,從名字可以看出採用的是共享模式。

640?wx_fmt=png

tryAcquireShared程式碼在Sync中被實現如下:

640?wx_fmt=png

如果state等於0返回1,否則返回-1;state等於0說明沒有物件在同步器中,執行緒可以繼續執行下去,否則進入doAcquireSharedInterruptibly方法中,doAcquireSharedInterruptibly方法如下:

640?wx_fmt=png

這段程式碼就是共享模式獲取節點,獲取不到就進入佇列中休眠,這個跟讀寫鎖一樣,知道state等於0後被喚醒。

countDown方法如下:

640?wx_fmt=png

呼叫的是Sync的releaseShared方法,

640?wx_fmt=png

640?wx_fmt=png

countDown方法的主要功能就是通過CAS方法減少state的值,減少成功後喚醒佇列中的節點。喚醒主節點成功後doAcquireSharedInterruptibly中方法會繼續執行接著判斷state是否等於0,不等與繼續休眠否則繼續執行執行緒。

Semaphore

Semaphore可以控制訪問執行緒的數量。

用例:

640?wx_fmt=png

原理分析

首先看構造方法,

640?wx_fmt=png

預設構造方法採用非公平模式。

acquire方法如下:

640?wx_fmt=png

很熟悉預設採用的是共享模式獲取節點資訊,跟讀鎖類似。

640?wx_fmt=png

 

release方法如下:

640?wx_fmt=png

acquireSharedInterruptibly方法如下:

640?wx_fmt=png

tryReleaseShared方法如下:

640?wx_fmt=png 

總結

CyclicBarrier主要用於N個執行緒之間互斥,當且僅當N個執行緒都執行到屏障處所有執行緒才能繼續執行下去,CyclicBarrier可以被重複使用,CyclicBarrier通過可衝入鎖+AQS+Condition實現,CyclicBarrier呼叫await方法獲取可重入鎖同時減少state的值,state==0時喚醒所有正在等待的執行緒,否則執行緒處於等待狀態,執行緒間的通訊主要通過Condition機制來實現。

CountDownLatch主要用於某個執行緒等待N個執行緒執行完後等待的執行緒接著繼續執行下去,不能夠重複執行,CountDownLatch通過設施AQS state值來實現,每次呼叫counDown方法後都去喚醒正在等待的執行緒,等待的執行緒判斷state是否等於0,等於0就繼續執行。

Semaphore用於控制訪問執行緒的數量,Semaphore通過設定AQS state值來實現,呼叫require方法後cas減少state的值,如果state值為負數說明有更多執行緒正在訪問程式碼塊,這是後需要把這些執行緒休眠,呼叫release方法後重新增加state值,重新增加state值後去喚醒正在等待的執行緒。

640?wx_fmt=png

公眾號推薦:

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

相關文章