Java多線程工具類之循環柵欄計數器

Java多線程下循環計數器

本文主要內容:CyclicBarrier(下文中凱哥就用cycBar來代替)定義介紹;舉例說明;代碼演示;從源碼來看原理及總結;CyclicBarrier與CountDownLatch(下文就用CountDown來代替)比較。

本篇是《凱哥(凱哥Java:kagejava)併發編程學習》系列之《併發工具類》教程的第二篇:《Java多線程下循環計數器》。

Java多線程工具類之循環柵欄計數器

一:CyclicBarrier是什麼

cycBar是什麼呢?

來看看JDKAPI文檔中是怎麼介紹這個對象的:

Java多線程工具類之循環柵欄計數器


翻譯後大概意思:允許一組線程全部等待彼此達到共同的屏障點的同步輔助。循環阻塞在涉及固定大小的線程方的程序中很有用,這些線程必須偶爾等待彼此。屏障被稱為循環 ,因為它可以在等待的線程被釋放之後重新使用。

有沒有這種感覺:每個漢字都認識,但是放在一起就不知道什麼意思了?對!沒錯,就是這種感覺~~~///(^v^)\\\\\\~~~。上面翻譯簡單一句話就是:有個可以循環利用的集合點。作用就是讓所有線程都到達這個集合點後,才會繼續下一步行動。如果還是不理解,請看下下面生活中的例子。

二:CyclicBarrier生活中例子理解

在生活中,如果我們跟團旅遊的話,就更容易理解了。假設一個團有7個人,旅遊團安排的旅遊路線是八達嶺長城故宮這個路線的一日遊。遊玩時間是3小時。三個小時後, 統一都到八達嶺的集合點:入口處。點名等人員都到齊後,發車到下一個景點。這種場景相信大家都遇到過吧。八達嶺入口的集合點不僅僅這個旅遊團可以使用,其他的旅遊團都可以使用的。如果站在多線程併發場景下來分析的話:旅遊團中每個成員都是一個線程,入口集合點就是屏障(Barrier),每個成員都必須到達集合點(循環到達Cyclic)且人數和旅遊團人數相等的時候,才能觸發旅遊車發車去下一個景點的線程。

還有一個例子更容易理解:集齊七龍珠,召喚神龍。相信看過《七龍珠》的都知道這個吧。想要召喚神龍的觸發點就是集齊七個龍珠。

通過上面案例,大家是不是更容易理解了?下面凱哥(kaigejava)將通過代碼實現集齊七龍珠召喚神龍的操作。

三:代碼演示

需求:集齊七顆龍珠,召喚神龍。

3.1:未使用cycbarr的時候

使用七個線程,來代替找龍珠的七個任務。每個線程在找龍珠的時候,耗時2s.就sleep。最後,七個線程執行完成之後,使用召喚神龍的線程來召喚神龍。代碼如下圖:

Java多線程工具類之循環柵欄計數器


運行結果:

Java多線程工具類之循環柵欄計數器


我們發現,龍珠還沒有找到呢,神龍就出現了。這個當然是不對的。所以不使用cycBarr這個操作是不對的。

3.2:使用cycbarr

Java多線程工具類之循環柵欄計數器


查看運行結果:

Java多線程工具類之循環柵欄計數器


當七顆龍珠都找到之後,才可以召喚神龍。 符合我們的需求。那麼,cycbarr的實現原理是什麼呢?接下來我們從源碼來看看運行原理。

四:從源碼來看原理及總結

4.1:構造器

Java多線程工具類之循環柵欄計數器


有兩個構造器,給定一個int的parties和兩個參數的構造器。參數含義:

Int parties:給定參與的線程的個數。也可以理解為屏障的值,當達到這個值之後,屏障將會跳閘執行其他任務(在集齊龍珠案例中,可以理解為需要7個線程來執行。);

Runnable barrierAction:這個參數意思是指當線程達到屏障數量後,屏障跳閘後執行給定線程的任務(在集齊龍珠案例中,可以理解為當集齊七顆龍珠後,需要執行召喚神龍的操作)。

4.2:幾個重要的成員屬性

Java多線程工具類之循環柵欄計數器


其中使用了ReentrantLock這個可重入鎖作為併發的鎖對象。使用Codition這個對象來實現等待/通知模式。

Java多線程工具類之循環柵欄計數器


4.3:重要方法

Java多線程工具類之循環柵欄計數器


無論是await()還是await(long timeout,TimeUnit unit)這兩個await最後都是調用dowait()方法。

Dowait方法主要乾了什麼?其實邏輯處理比較簡單的。如果當前線程不是最後一個調用await方法的線程,則會一直自旋等待著。源碼如下:

Java多線程工具類之循環柵欄計數器


當發生以下清空的時候,就會在自旋等待了:

1:當前執行的線程是最後一個線程。即index == 0成立的時候;

2:當參與其中的某個線程在等待的時候,等待超時了;

3:參與的線程中某一個線程被中斷了;

4:在調用了CycBarr的reset方法後。該方法將會將對應的屏障(parties)重置為初始狀態。

對應源碼如下:

Java多線程工具類之循環柵欄計數器


Java多線程工具類之循環柵欄計數器


4.4:總結

語法:

默認使用兩個參數的構造器。然後再try代碼塊中調用await方法。如下圖:

Java多線程工具類之循環柵欄計數器


五:CyclicBarrier與CountDownLatch比較

關於CountDownLatch的相關介紹,凱哥(kaigejava)在另一篇文章《Java多線程併發容器之併發倒計時器》中做了詳細介紹。歡迎大家去查看.

CountDown:

計數器只能夠使用一次;

參與的線程的職責是不一樣的(火箭發射,不同部門做的事情不一樣)。有的再倒計時,有的再等待倒計時結束。

CycBarr:

是可以循環利用的,因為可以使用reset方法將屏障重置,可以使用多次,所有cycBar能夠處理更為複雜的場景;

參與的線程職責是一樣的(都是找龍珠);

提供了其他的方法。如獲取當前阻塞的線程數量的getnumberWaiting方法。用於判斷當前線程阻塞的線程是否被中斷的isBroken方法。

從喚起阻塞線程角度來看的話:

CountDownLatch運行一個或者是多個線程等待一組事件的產生,而CyclicBarrier用於等待其他線程運行到屏障(柵欄)位置。

從適用場景角度來說:

CycBarr適用於多個線程結果元素的合併操作。

如需要從多個excel中統計數量的時候,可以使用CycBarr來從不同的excel讀取到數據之後,在進行彙總操作。


分享到:


相關文章: