Java中的CyclicBarrier是JDK 5中java.util.Concurrent包中引入的同步器,以及其他并發實用程序(如Counting Semaphore , BlockingQueue , ConcurrentHashMap等)。CyclicBarrier與CountDownLatch類似,我們在上一篇文章中看到了它,它允許多個線程等待彼此(障礙),然后繼續。 CoundDownLatch和CyclicBarrier之間的區別也是Java中一個非常流行的多線程面試問題 。 CyclicBarrier是并發程序的自然要求,因為一旦單個任務完成,它就可以用于執行任務的最后一部分。 等待彼此到達屏障的所有線程都稱為方,使用要等待的方數初始化CyclicBarrier,然后通過調用CyclicBarrier.await()方法來彼此等待線程,這是Java中的阻塞方法,直到所有線程都阻塞或各方調用await()。 通常,調用await()會喊出Thread正在等待屏障。 await()是一個阻塞調用,但可以被其他線程超時或中斷。 在此Java并發性教程中,我們將看到CyclicBarrier的簡單示例,在該示例上,三個線程將互相等待,然后再繼續操作。
Java中 CountDownLatch 和 CyclicBarrier 之間的區別
在上一篇文章中,我們了解了如何使用CountDownLatch來實現多個相互等待的線程 。 如果您查看CyclicBarrier,它也做同樣的事情,但是有不同之處,一旦計數達到零,您將無法重用 CountDownLatch ,而您可以通過調用reset()方法重用CyclicBarrier來將Barrier重置為其初始狀態。 這意味著CountDownLatch適用于一次事件,例如應用程序啟動時間,而CyclicBarrier可以用于周期性事件,例如同時計算大問題的解決方案等。如果您想了解有關Java中線程和并發性的更多信息,也可以查看我有關何時在Java中使用Volatile變量以及Java 如何同步的文章 。
Java中的 CyclicBarrier –示例

這是Java中CyclicBarrier的一個簡單示例,在該示例中,我們使用3個方初始化了CyclicBarrier,這意味著為了越過障礙,3個線程需要調用await()方法。 每個線程都在短時間內調用await方法,但是直到所有3個線程都到達障礙為止,它們才繼續進行,一旦所有線程到達障礙,障礙都獲得代理,并且每個線程從此處開始執行。 通過以下CyclicBarrier示例在Java中的輸出,可以很清楚地看到它:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.logging.Level;
import java.util.logging.Logger;/**
* Java program to demonstrate how to use CyclicBarrier in Java. CyclicBarrier is a
* new Concurrency Utility added in Java 5 Concurrent package.
*
* @author Javin Paul
*/public class CyclicBarrierExample {//Runnable task for each thread
private static class Task implements Runnable {private CyclicBarrier barrier;public Task(CyclicBarrier barrier) {
this.barrier = barrier;
}@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " is waiting on barrier");
barrier.await();
System.out.println(Thread.currentThread().getName() + " has crossed the barrier");
} catch (InterruptedException ex) {
Logger.getLogger(CyclicBarrierExample.class.getName()).log(Level.SEVERE, null, ex);
} catch (BrokenBarrierException ex) {
Logger.getLogger(CyclicBarrierExample.class.getName()).log(Level.SEVERE, null, ex);
}
}
}public static void main (String args[]) {//creating CyclicBarrier with 3 parties i.e. 3 Threads needs to call await()
final CyclicBarrier cb = new CyclicBarrier(3, new Runnable(){
@Override
public void run(){
//This task will be executed once all thread reaches barrier
System.out.println("All parties are arrived at barrier, lets play");
}
});//starting each of thread
Thread t1 = new Thread(new Task(cb), "Thread 1");
Thread t2 = new Thread(new Task(cb), "Thread 2");
Thread t3 = new Thread(new Task(cb), "Thread 3");t1.start();
t2.start();
t3.start();}
}
輸出:
Thread 1 is waiting on barrier
Thread 3 is waiting on barrier
Thread 2 is waiting on barrier
All parties are arrived at barrier, lets play
Thread 3 has crossed the barrier
Thread 1 has crossed the barrier
Thread 2 has crossed the barrier
何時 在Java中 使用 CyclicBarrier
鑒于CyclicBarrier的性質, 與Java 7的fork-join框架類似,實現map reduce任務非常方便,在Java 7中 ,將大任務分解為較小的部分,并完成需要從單個小任務輸出的任務,例如要計算印度的人口,您可以有4個線程來計算北,南,東和西的人口,完成后它們可以互相等待,當最后一個線程完成任務時,主線程或任何其他線程可以從每個區域中添加結果并打印總人口。 您可以在Java中使用CyclicBarrier:
1)實現多人游戲,直到所有玩家都加入后才能開始。
2)通過將其分解為較小的單個任務來執行冗長的計算,通常要實施Map reduce技術。
Java 中 CyclicBarrier的 重點
1.一旦所有線程到達barrier,CyclicBarrier即可執行完成任務,可以在創建CyclicBarrier時提供。
2.如果用3個參與者初始化了CyclicBarrier,則意味著3個線程需要調用await方法來打破該障礙。
3. 線程將在await()上阻塞 ,直到各方到達障礙,另一個線程中斷或等待超時為止。
4.如果另一個線程中斷正在等待屏障的線程,它將拋出BrokernBarrierException,如下所示:
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:172)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:327)
5. CyclicBarrier .reset()將Barrier置于其初始狀態,正在等待或尚未達到屏障的其他線程將以java.util.concurrent.BrokenBarrierException終止。
以上就是Java中帶有示例的CyclicBarrier。 我們還看到了Java中CountDownLatch和CyclicBarrier之間的區別,并且了解了一些可以在Java并發代碼中使用CyclicBarrier的想法。
參考: Javarevisited博客上的JCG合作伙伴 Javin Paul提供的Java 5中的CyclicBarrier示例–并發教程 。
翻譯自: https://www.javacodegeeks.com/2012/08/java-concurrency-cyclicbarrier-example.html