CyclicBarrier是一個同步輔助類,它容許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 頗有用。由於該 barrier 在釋放等待線程後能夠重用,因此稱它爲循環 的 barrier。app
通俗點講就是:讓一組線程到達一個屏障時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,全部被屏障攔截的線程纔會繼續幹活。ide
CyclicBarrier字面意思迴環柵欄,經過它能夠實現讓一組線程等待至某個狀態以後再所有同時執行。叫作迴環是由於當全部等待線程都被釋放之後,CyclicBarrier能夠被重用。咱們暫且把這個狀態就叫作barrier,函數
當調用await()方法以後,線程就處於barrier了。源碼分析
先來個demo:spa
運行結果:線程
代碼中設置了兩個屏障點,第一個用於召集7個法師,等7個法師召集完後,在設置在一個屏障點,7位法師去尋找龍珠,而後召喚神龍,中間有個嵌套的關係!orm
源碼分析對象
上述的例子,大體說了一下屏障,由於設置了兩個屏障,並無演示上述說的可循環使用(Cyclic)的屏障(Barrier) 中的可循環使用(Cyclic)。ci
查看 CyclicBarrier.reset() 可知,可使 CyclicBarrier 回到最初始的狀態,因爲使用的相對較少,這裏再也不演示。get
CyclicBarrier構造方法
能夠看得出CyclicBarrier的內部是使用重入鎖ReentrantLock和Condition。它有兩個構造函數:
CyclicBarrier(int parties):建立一個新的 CyclicBarrier,它將在給定數量的參與者(線程)處於等待狀態時啓動,但它不會在啓動 barrier 時執行預約義的操做。
CyclicBarrier(int parties, Runnable barrierAction) :建立一個新的 CyclicBarrier,它將在給定數量的參與者(線程)處於等待狀態時啓動,並在啓動 barrier 時執行給定的屏障操做,該操做由最後一個進入 barrier 的線程執行。
parties表示攔截線程的數量。
barrierAction 爲CyclicBarrier接收的Runnable命令,用於在線程到達屏障時,優先執行barrierAction ,用於處理更加複雜的業務場景。
在CyclicBarrier中最重要的方法莫過於await()方法,在全部參與者都已經在此 barrier 上調用 await 方法以前,將一直等待。以下:
第二個參數0,說明不是超時等待
其實await()的處理邏輯仍是比較簡單的:若是該線程不是到達的最後一個線程,則他會一直處於等待狀態,除非發生如下狀況:
最後一個線程到達,即index == 0
超出了指定時間(超時等待)
其餘的某個線程中斷當前線程
其餘的某個線程中斷另外一個等待的線程
其餘的某個線程在等待barrier超時
其餘的某個線程在此barrier調用reset()方法。reset()方法用於將屏障重置爲初始狀態。
在上面的源代碼中,咱們可能須要注意Generation 對象,在上述代碼中咱們老是能夠看到拋出BrokenBarrierException異常,那麼何時拋出異常呢?若是一個線程處於等待狀態時,若是其餘線程調用reset(),或者調用的barrier本來就是被損壞的,則拋出BrokenBarrierException異常。同時,任何線程在等待時被中斷了,則其餘全部線程都將拋出BrokenBarrierException異常,並將barrier置於損壞狀態。
同時,Generation描述着CyclicBarrier的更顯換代。在CyclicBarrier中,同一批線程屬於同一代。當有parties個線程到達barrier,generation就會被更新換代。其中broken標識該當前CyclicBarrier是否已經處於中斷狀態。
默認barrier是沒有損壞的。
當barrier損壞了或者有一個線程中斷了,則經過breakBarrier()來終止全部的線程:
在breakBarrier()中除了將broken設置爲true,還會調用signalAll將在CyclicBarrier處於等待狀態的線程所有喚醒。
當全部線程都已經到達barrier處(index == 0),則會經過nextGeneration()進行更新換地操做,在這個步驟中,作了三件事:
喚醒全部線程
重置count
generation
CyclicBarrier同時也提供了await(long timeout, TimeUnit unit) 方法來作超時控制:
能夠看出其內部仍是經過調用
private int dowait(boolean timed, long nanos)
實現的。
CyclicBarrier 和 CountDownLatch 的區別
CountDownLatch 的計數器只能使用一次。而 CyclicBarrier 的計數器可使用 reset() 方法重置。因此 CyclicBarrier 能處理更爲複雜的業務場景,好比若是計算髮生錯誤,能夠重置計數器,並讓線程們從新執行一次。
CyclicBarrier 還提供其餘有用的方法,好比 getNumberWaiting 方法能夠得到 CyclicBarrier 阻塞的線程數量。isBroken 方法用來知道阻塞的線程是否被中斷。好比如下代碼執行完以後會返回 true。
CountDownLatch 會阻塞主線程,CyclicBarrier 不會阻塞主線程,只會阻塞子線程。