1. 程式人生 > >Java併發程式設計的藝術筆記(七)——CountDownLatch和CyclicBarrier

Java併發程式設計的藝術筆記(七)——CountDownLatch和CyclicBarrier

一.等待多執行緒完成的CountDownLatch

CountDownLatch允許一個或多個執行緒等待其他執行緒完成操作

例:

1)開啟多個執行緒分塊下載一個大檔案,每個執行緒只下載固定的一截,最後由另外一個執行緒來拼接所有的分段;解析一個Excel裡多個sheet的資料,此時可以考慮使用多執行緒,每個          執行緒解析一個sheet裡的資料,等到所有的sheet都解析完之後,程式需要提示解析完成。

2)應用程式的主執行緒希望在負責啟動框架服務的執行緒已經啟動所有的框架服務之後再執行。

3)確保一個計算不會執行,直到所需要的資源被初始化。

 

CountDownLatch典型用法1:某一執行緒在開始執行前等待n個執行緒執行完畢。將CountDownLatch的計數器初始化為n new CountDownLatch(n) ,每當一個任務執行緒執行完畢,就將計數器減1 countdownlatch.countDown(),當計數器的值變為0時,在CountDownLatch上 await() 的執行緒就會被喚醒。一個典型應用場景就是啟動一個服務時,主執行緒需要等待多個元件載入完畢,之後再繼續執行。

 

CountDownLatch典型用法2:實現多個執行緒開始執行任務的最大並行性。注意是並行性,不是併發,強調的是多個執行緒在某一時刻同時開始執行。類似於賽跑,將多個執行緒放到起點,等待發令槍響,然後同時開跑。做法是初始化一個共享的CountDownLatch(1),將其計數器初始化為1,多個執行緒在開始執行任務前首先 coundownlatch.await(),當主執行緒呼叫 countDown() 時,計數器變為0,多個執行緒同時被喚醒。

CountDownLatch的不足

CountDownLatch是一次性的,計數器的值只能在構造方法中初始化一次,之後沒有任何機制再次對其設定值,當CountDownLatch使用完畢後,它不能再次被使用。

特有方法:

public CountDownLatch(int count); //指定計數的次數,只能被設定1次
public void countDown();          //呼叫此方法則計數減1
public void await() throws InterruptedException   //呼叫此方法會一直阻塞當前執行緒,直到計時器的值為0,除非執行緒被中斷。
Public Long getCount();           //
得到當前的計數 Public boolean await(long timeout, TimeUnit unit) //呼叫此方法會一直阻塞當前執行緒,直到計時器的值為0,除非執行緒被中斷或者計數器超時,返回false代表計數器超時

From Object Inherited:

Clone、equals、hashCode、notify、notifyALL、wait等。

二.同步屏障CyclicBarrier

CyclicBarrier可以使一定數量的執行緒反覆地在柵欄位置處彙集。

當執行緒到達柵欄位置時將呼叫await方法,這個方法將阻塞直到所有執行緒都到達柵欄位置。如果所有執行緒都到達柵欄位置,那麼柵欄將開啟,此時所有的執行緒都將被釋放,而柵欄將被重置以便下次使用。

CyclicBarrier可以用於多執行緒計算資料,最後合併計算結果的場景。例如,用一個Excel儲存了使用者所有銀行流水,每個Sheet儲存一個賬戶近一年的每筆銀行流水,現在需要統計使用者的日均銀行流水,先用多執行緒處理每個sheet裡的銀行流水,都執行完之後,得到每個sheet的日均銀行流水,最後,再用barrierAction用這些執行緒的計算結果,計算出整個Excel的日均銀行流水

三.CyclicBarrier和CountDownLatch的區別

CountDownLatch的計數器只能使用一次,而CyclicBarrier的計數器可以使用reset()方法重置,可以使用多次,所以CyclicBarrier能夠處理更為複雜的場景;

CyclicBarrier還提供了一些其他有用的方法,比如getNumberWaiting()方法可以獲得CyclicBarrier阻塞的執行緒數量,isBroken()方法用來了解阻塞的執行緒是否被中斷;CountDownLatch允許一個或多個執行緒等待一組事件的產生,而CyclicBarrier用於等待其他執行緒執行到柵欄位置。