循環屏障CyclicBarrier以及和CountDownLatch的區別


答案:CountdownLatch阻塞主線程,等所有子線程完結了再繼續下去。Syslicbarrier阻塞一組線程,直至某個狀態之后再全部同時執行,並且所有線程都被釋放后,還能通過reset來重用。

 

CyclicBarrier 的字面意思是可循環使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續干活。

這個屏障之所以用循環修飾,是因為在所有的線程釋放彼此之后,這個屏障是可以重新使用的(reset()方法重置屏障點)。這一點與CountDownLatch不同

CyclicBarrier

CyclicBarrier,讓一組線程到達一個同步點后再一起繼續運行,在其中任意一個線程未達到同步點,其他到達的線程均會被阻塞。

 

CyclicBarrier是一種同步機制允許一組線程相互等待,等到所有線程都到達一個屏障點才退出await方法,它沒有直接實現AQS而是借助ReentrantLock來實現的同步機制。它是可循環使用的,而CountDownLatch是一次性的,另外它體現的語義也跟CountDownLatch不同,CountDownLatch減少計數到達條件采用的是release方式,而CyclicBarrier走向屏障點(await)采用的是Acquire方式,Acquire是會阻塞的,這也實現了CyclicBarrier的另外一個特點,只要有一個線程中斷那么屏障點就被打破,所有線程都將被喚醒(CyclicBarrier自己負責這部分實現,不是由AQS調度的),這樣也避免了因為一個線程中斷引起永遠不能到達屏障點而導致其他線程一直等待。屏障點被打破的CyclicBarrier將不可再使用(會拋出BrokenBarrierException)除非執行reset操作。

 

CyclicBarrier源碼分析

  • 構造方法
    CyclicBarrier提供兩個構造方法CyclicBarrier(int parties)CyclicBarrier(int parties, Runnable barrierAction)
     
    CyclicBarrier構造方法
    • CyclicBarrier(int parties)
      默認構造方法,參數表示攔截的線程數量

    • CyclicBarrier(int parties, Runnable barrierAction)
      由於線程之前的調度是由CPU決定的,所以默認的構造方法無法設置線程執行優先級,CyclicBarrier提供一個更高級的構造函數CyclicBarrier(int parties, Runnable barrierAction),用於在線程到達同步點時,優先執行線程barrierAction,這樣可以更加方便的處理一些負責的業務場景。

創建CyclicBarrier后,每個線程調用await方法告訴CyclicBarrier自己已經到達同步點,然后當前線程被阻塞。接下來我們來看看await方法的具體實現。

  • await實現
    CyclicBarrier同樣提供帶超時時間的await和不帶超時時間的await:


     
    await實現

    整個await方法的核心是dowait方法的調用,我們來看看dowait的具體實現。

  • dowait實現

    1. 在dowait的前段部分,主要完成了當所有線程都到達同步點(barrier)時,喚醒所有的等待線程,一起往下繼續運行,可根據參數barrierAction決定優先執行的線程。


       
      dowait實現前半部分
    2. 在dowait的實現后半部分,主要實現了線程未到達同步點(barrier)時,線程進入Condition自旋等待,直到等待超時或者所有線程都到達barrier時被喚醒。

     
    dowait實現后半部分

    在整個dowait:

    1. 使用ReentrantLock保證每一次操作線程安全;
    2. 線程等待/喚醒使用Lock配合Condition來實現;
    3. 線程被喚醒的條件:等待超時或者所有線程都到達barrier。

到這里為止,CyclicBarrier的重要實現源碼分析就結束了,接下來還是照樣給出一個具體的使用案例,方便掌握CyclicBarrier的具體用法。

CyclicBarrier使用案例

需求:多線程計算數據,merge計算結果。

代碼實現

注意紅框部分:線程都達到barrier后執行當前類的run方法

 
使用案例

運行結果:

 
從運行結果可看出執行完一輪后又開始執行了

CyclicBarrier和CountDownLatch都可以實現線程等待,那么它倆之間的區別是什么呢?

CyclicBarrier和CountDownLatch的區別

看了各種資料和書,大家一致的意見都是CountDownLatch是計數器,只能使用一次,而CyclicBarrier的計數器提供reset功能,可以多次使用。但是我不那么認為它們之間的區別僅僅就是這么簡單的一點。我們來從jdk作者設計的目的來看,javadoc是這么描述它們的:

CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

CyclicBarrier : A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.

從javadoc的描述可以得出:

  • CountDownLatch:一個或者多個線程,等待其他多個線程完成某件事情之后才能執行;
  • CyclicBarrier:多個線程互相等待,直到到達同一個同步點,再繼續一起執行

對於CountDownLatch來說,重點是“一個線程(多個線程)等待”,而其他的N個線程在完成“某件事情”之后,可以終止,也可以等待。而對於CyclicBarrier,重點是多個線程,在任意一個線程沒有完成,所有的線程都必須互相等待,然后繼續一起執行

CountDownLatch是計數器,線程完成一個記錄一個,只不過計數不是遞增而是遞減,而CyclicBarrier更像是一個閥門,需要所有線程都到達,閥門才能打開,然后繼續執行。




鏈接:https://www.jianshu.com/p/bce9f156080f


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM