網(wǎng)上有很多文章都討論了CountDownLatch和CyclicBarrier的應(yīng)用場(chǎng)景,但是大部分CyclicBarrier的應(yīng)用場(chǎng)景都跟實(shí)際情況相去甚遠(yuǎn)。
先來(lái)看看CountDownLatch:
CountDown 的意思是 倒計(jì)時(shí),Latch 的意思是 門(mén)閂 。
JDK 釋中是這樣描述的:
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
- 讓一個(gè)或多個(gè)線程持續(xù)等待,直到其他多線程執(zhí)行的一組操作全部完成以后,這些等待的線程才會(huì)繼續(xù)執(zhí)行。
CountDownLatch的使用場(chǎng)景:
1. 讓單個(gè)線程等待多個(gè)線程
例如:一個(gè)服務(wù)需要從3個(gè)遠(yuǎn)程接口獲取數(shù)據(jù),就可以開(kāi)三個(gè)線程并調(diào)用遠(yuǎn)程接口,等待所有遠(yuǎn)程接口數(shù)據(jù)返回之后,服務(wù)線程再繼續(xù)執(zhí)行。
在比如:并發(fā)計(jì)算,匯總結(jié)果。
2. 讓多個(gè)線程等待
例如:模擬秒殺場(chǎng)景,讓一組線程同時(shí)等待,同時(shí)恢復(fù)執(zhí)行,實(shí)現(xiàn)最大程度的并行性。
注意:當(dāng)高并發(fā)請(qǐng)求時(shí),countdownlatch的await方法有可能會(huì)引起死鎖。
如果線程池中線程的數(shù)量較少,在高并發(fā)時(shí)會(huì)出現(xiàn)多個(gè)請(qǐng)求占用了全部的線程,但是每個(gè)請(qǐng)求又需要await其他線程,被等待的線程拿不到線程資源無(wú)法執(zhí)行,導(dǎo)致多個(gè)請(qǐng)求同時(shí)進(jìn)入線程阻塞,最后形成死鎖。
解決方法:使用自定義線程池,擴(kuò)大線程數(shù)量,并且建立線程池拒絕機(jī)制。
再來(lái)看看 CyclicBarrier
Cyclic 的意思是 循環(huán) ,Barrier 的意思是 屏障 。
JDK 注釋中是這樣描述的:
A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other.
The barrier is called cyclic because it can be re-used after the waiting threads are released.
- CyclicBarrier 是一個(gè)同步輔助類(lèi),它允許一組線程相互等待直到所有線程都到達(dá)一個(gè)公共的屏障點(diǎn)。
- 在程序中有固定數(shù)量的線程,這些線程有時(shí)候必須等待彼此,這種情況下,使用 CyclicBarrier 很有幫助。
- 這個(gè)屏障之所以用循環(huán)修飾,是因?yàn)樵谒械木€程釋放彼此之后,這個(gè)屏障是可以重新使用的。
CyclicBarrier的應(yīng)用場(chǎng)景:
生活中我們會(huì)約朋友們到某個(gè)餐廳一起吃飯,有些朋友可能會(huì)早到,有些朋友可能會(huì)晚到,但是餐廳規(guī)定必須等到所有人到齊之后才會(huì)上菜。這里的朋友們就是各個(gè)線程,餐廳就是 CyclicBarrier。
- 這樣的例子有助于理解CyclicBarrier,但我相信開(kāi)發(fā)中一定不會(huì)遇到這樣的場(chǎng)景。
CyclicBarrier可以用于多線程計(jì)算數(shù)據(jù),最后合并計(jì)算結(jié)果的應(yīng)用場(chǎng)景。比如現(xiàn)在需要計(jì)算10個(gè)人12個(gè)月的工資,可以開(kāi)10個(gè)worker線程,分別計(jì)算每個(gè)人的工資,最后,再用barrierAction將這些線程的計(jì)算結(jié)果進(jìn)行整合,得出最后結(jié)果。
- barrierAction不需要在主線程中執(zhí)行,這是CyclicBarrier的優(yōu)勢(shì),但是其代價(jià)是阻塞了所有的worker線程。
- worker線程計(jì)算完成之后,把結(jié)果保存就可以釋放線程了,用了CyclicBarrier把線程都阻塞了,然后統(tǒng)一釋放,這是什么設(shè)計(jì)?
CyclicBarrier強(qiáng)調(diào)線程之間相互等待
受經(jīng)驗(yàn)所限,在實(shí)際開(kāi)發(fā)中,我還沒(méi)有需要需要線程相互等待的例子,而且這樣的場(chǎng)景特別容易造成死鎖。
CyclicBarrier強(qiáng)調(diào)循環(huán)
多輪并行計(jì)算:如果需要計(jì)算N組人一年的平均工資,每組需要多個(gè)線程并行計(jì)算,計(jì)算完一組,再開(kāi)始下一組,這樣就需要多輪并行計(jì)算。CyclicBarrier 比 CountDownLatch 更適合這樣的場(chǎng)景。
CountDownLatch與CyclicBarrier的區(qū)別:
- CountDownLatch的計(jì)數(shù)器只能使用一次。而CyclicBarrier的計(jì)數(shù)器可以使用reset() 方法重置
- CyclicBarrier能處理更為復(fù)雜的業(yè)務(wù)場(chǎng)景,比如計(jì)算發(fā)生錯(cuò)誤,可以結(jié)束阻塞,重置計(jì)數(shù)器,重新執(zhí)行程序
- CyclicBarrier還提供getNumberWaiting(可以獲得CyclicBarrier阻塞的線程數(shù)量)、isBroken(用來(lái)知道阻塞的線程是否被中斷)等方法
- CountDownLatch會(huì)阻塞主線程,CyclicBarrier不會(huì)阻塞主線程,只會(huì)阻塞子線程