CyclicBarrier和CountDownLatch一樣是一種同步輔助工具
CyclicBarrier 它允許一組線程在一個共同的屏障點彼此等待,所有線程到達屏障點後再全部同時執行。固定數量的線程在程序中必須彼此等待的時候,CyclicBarrier非常有用
同CountDownLatch不同的是:
- CyclicBarrier的某個線程運行到某個點上之後,該線程即停止運行,直到所有的線程都到達了這個點,所有線程才重新運行;CountDownLatch則不是,某線程運行到某個點上之後,只是給某個數值-1而已,該線程繼續運行
- CyclicBarrier只能喚起一個任務,CountDownLatch可以喚起多個任務
- CyclicBarrier可重用,CountDownLatch不可重用,計數值爲0該CountDownLatch就不可再用了
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CyclicBarrier;
public class Person implements Runnable {
private CyclicBarrier barrier;
private String name;
public Person(CyclicBarrier barrier, String name) {
this.barrier = barrier;
this.name = name;
}
@Override
public void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
System.out.println(sdf.format(new Date()) + " " + name + "出發去飯店");
System.out.println(sdf.format(new Date()) + " " + name + "到了飯店");
barrier.await();
System.out.println(sdf.format(new Date()) + " " + name + "開始喫飯");
System.out.println(sdf.format(new Date()) + " " + name + "喫完了");
// 重用CyclicBarrier
barrier.await();
System.out.println(sdf.format(new Date()) + " " + name + "離開餐廳");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
CyclicBarrier barrier = new CyclicBarrier(3);
List<Thread> threads = new ArrayList<>(3);
threads.add(new Thread(new Person(barrier, "張三")));
threads.add(new Thread(new Person(barrier, "李四")));
threads.add(new Thread(new Person(barrier, "王五")));
for (Thread thread : threads) {
thread.start();
}
//等待所有線程跑完
for (Thread thread : threads) {
thread.join();
}
}
經過測試:當使用 CyclicBarrier 和 不使用 CyclicBarrier
使用 CyclicBarrier:
17:31:42.395 張三出發去飯店
17:31:42.395 李四出發去飯店
17:31:42.396 張三到了飯店
17:31:42.395 王五出發去飯店
17:31:42.396 李四到了飯店
17:31:42.396 王五到了飯店
17:31:42.397 王五開始喫飯
17:31:42.397 張三開始喫飯
17:31:42.397 李四開始喫飯
17:31:42.397 張三喫完了
17:31:42.397 王五喫完了
17:31:42.397 李四喫完了
17:31:42.397 張三離開餐廳
17:31:42.397 李四離開餐廳
17:31:42.397 王五離開餐廳
不使用 CyclicBarrier:
17:27:36.764 張三出發去飯店
17:27:36.767 張三到了飯店
17:27:36.768 張三開始喫飯
17:27:36.768 張三喫完了
17:27:36.768 張三離開餐廳
17:27:36.764 王五出發去飯店
17:27:36.764 李四出發去飯店
17:27:36.769 李四到了飯店
17:27:36.769 李四開始喫飯
17:27:36.769 李四喫完了
17:27:36.769 李四離開餐廳
17:27:36.769 王五到了飯店
17:27:36.770 王五開始喫飯
17:27:36.770 王五喫完了
17:27:36.770 王五離開餐廳
原理:
- 在CyclicBarrier的內部定義了一個ReentrantLock的對象,然後再利用這個ReentrantLock對象生成一個Condition的對象
- 每當一個線程調用CyclicBarrier的await方法時,首先把剩餘屏障的線程數減1
- 然後判斷剩餘屏障數是否爲0:如果不是,利用Condition的await方法阻塞當前線
- 如果是,首先利用Condition的signalAll方法喚醒所有線程
- 最後重新生成Generation對象以實現屏障的循環使用
參考:
https://zhuanlan.zhihu.com/p/140324377?from_voters_page=true