Java並發基礎-柵欄(CountDownLatch)與閉鎖(CyclicBarrier)


1. 閉鎖CountDownLatch

閉鎖CountDownLatch用於線程間的同步,它可以使得一個或者多個線程等待其它線程中的某些操作完成。它有一個int類型的屬性count,當某個線程調用CountDownLatch對象的await方法時,將會阻塞,直到count的值變成0;count值可以通過它的countDown的方法進行減1。 count的值在構造方法中進行指定。

注意count的值不可以重設,因此當count的值變成0后,CountDownLatch就不再起作用了,此時再調用它的await方法將會直接返回。也就是說,對它的重復使用是沒有任何意義的。

它可以使用在以下場景:

當count的值為1時,可以作為一個開關,所有調用它的await方法的線程都一起等待,直到開關被某個其它線程打開;

當count的值為n時,可以使得一個或者多個線程等待其它n個線程完成了某些處理,或者某個線程執行了n次某項操作;

典型的用法如:將一個計算過程細分成n個子計算,主線程調用CountDownLatch的await方法等待子任務計算完成;而n個子線程處理每個子任務;當每個子任務執行完成后調用countDown方法。這樣子任務計算完成時主線程就可以繼續往下執行了。

注意:CountDownLatch本身是線程安全的,因此對它的方法的調用不需要再使用其它的同步機制。

1.1 示例

假設要主線程要等待其它一組線程執行完某個操作再繼續執行,可以使用以下方式:

直接運行,執行結果如下:

可以看到:主線程調用latch.await方法后即等待;當所有被提交的Work作業執行完latch.countDown后,主線程繼續執行,而不用等到所有子線程全部完成。

如果將latch.countDown()方法放在每個子線程的最后,那么就意味着主線程需要等待所有子線程執行完成了。這個時候就與線程池中使用Future中的get方法類似。

因此,在線程間的協作上,CountDownLatch可以進行更加精細的控制:某個線程可以依賴於其它線程執行部分后馬上執行,而不用等待依賴的線程全部執行完成后再執行!

1.2 CountDownLatch方法說明

閉鎖主要包含以下方法:

a. await() throws InterruptedException

如果count的值為0,那么該方法將直接返回;否則當前線程將會阻塞直到閉鎖的count值變成0或者當前線程被中斷。

b. boolean await(long timeout, TimeUnit unit) throws InterruptedException

如果count的值為0,那么該方法直接返回,否則將會阻塞直到閉鎖的count變成0或者當前線程被中斷或者超時時間到;當count變成0時返回True;否則如果超時時間到且未變成0則返回False。

c. countDown()

如果當前值已經是0則不會做任何事情; 否則將count的值減1;如果新值變成0的時候將會喚醒所有等待的線程;

d. long getCount()

返回當前的count值。

2.柵欄CyclicBarrier

柵欄是一種多線程之間的同步機制,它允許多個線程等待彼此直到每個線程都到達某個位置。它的名稱中含有cyclic是因為它可以重復使用。

如:有一張門有N把鑰匙,需要N把鑰匙組合到一起才能開門,大家商量好同時從不同地方向那張門趕去,先到的人必須要等待所有人都到達后才能打開門並進入。

2.1 使用示例

執行結果:

從結果中可以看出:直到三個線程都打印了第一條消息后,所有線程才繼續執行。

注意:通過構造函數,可以傳入需要等待的參與者個數。如果調用await的線程達到參與者個數,那么所有的參與者都會繼續往下執行;即使參與者個數大於指定的個數。

2.2CyclicBarrier的使用

主要是await與reset方法

a. await

阻塞當前線程,直到等待所有的參與者線程都調用了這個方法。當被中斷時拋出對應異常。它也可以指定超時時間,在超時時間到后直接返回。

b. reset

重置柵欄到初始化狀態,使得它可以繼續被使用。

3.柵欄與閉鎖的區別

經過以上分析,柵欄與閉鎖主要有以下區別:

閉鎖不可以重復使用,而柵欄提供了reset方法,可以重復使用。

使用場景上:閉鎖主要使用在一個或者多個線程等待某個條件的發生,這個條件一般是由其它非等待線程來進行更新;而柵欄多個線程等待的條件就是這些線程都運行到某個位置,而不能由這些線程以外的其它線程來進行控制。

注意實際上除了重復使用外,閉鎖也可以使用在柵欄的場景中,每個線程在調用閉鎖的await方法前都先調用countDown(),那與直接調用柵欄的await方法可以達到同樣的效果。


免責聲明!

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



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