CountDownLatch 、 CyclicBarrier 、Semaphore這三個java提供的工具經(jīng)常放在一起做比較,接下來三篇分別使用它們來區(qū)別他們的不同;先說說CyclicBarrier的個人理解,就像一個柵欄一樣,舉行賽跑的時候,所有的人必須全都到白線前等待,然后才開始;這里的白線就是CyclicBarrier,人就是線程;
- 構(gòu)造函數(shù)
首先看構(gòu)造函數(shù):
/**
* @Param parties : 需要計數(shù)的Thread數(shù)量,達到數(shù)量之后柵欄開放
* @Param barrierAction : 柵欄開放后觸發(fā)的動作
*/
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
// 這是個沒有動作的柵欄
public CyclicBarrier(int parties) {
this(parties, null);
}
- 常用方法
要了解如何用,需要看它的方法, 不分析原理看 public 的方法就行了;這里只看要用到的
// 調(diào)用這個方法,說明到達柵欄,會將到達線程的計數(shù)器加1
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
其他還有一些方法,比如:
限制時間的 await
重置柵欄的 reset
獲取等待線程數(shù)的 getNumberWaiting
查看柵欄開放狀態(tài)的 isBroken
這里簡單使用的話使用await方法就夠了;
- 簡單案例
我們構(gòu)造一個簡單場景,多線程統(tǒng)計單詞出現(xiàn)的次數(shù), 模擬一堆線程對數(shù)據(jù)操作全部完成之后在輸出結(jié)果
public static void main(String[] args) {
Map<String, Integer> map = new ConcurrentHashMap<>();
//創(chuàng)建一個100個計數(shù)的柵欄, 并且柵欄開放之后的方法是打印最終結(jié)果
CyclicBarrier cyclicBarrier = new CyclicBarrier(100, () -> {
System.out.println(map.get("test"));
});
// 100 線程操作map
for(int i = 0 ; i < 100; i++) {
new Thread(() -> {
try {
// 這里我們就模擬對 `test` 這個單詞的累加次數(shù)統(tǒng)計 這里使用了map的merge方法,這個方法是接口的默認(rèn)方法,但是在concurrentHashMap中進行了重寫, 可以看到他也是線程安全的;
Integer test = map.merge("test", 1, Integer::sum);
// 每個線程操作完畢,調(diào)用柵欄的await
cyclicBarrier.await();
// 當(dāng)柵欄開放這里才會執(zhí)行
System.out.println("mission result: " + test);
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
那么我們的CyclicBarrier在這里的作用是什么呢?其實這個在多線程單元測試的時候很常見,應(yīng)為這里是多線程的,在線程start完成之后,直接輸出map.get("test")的值的話,這個時候線程是沒有運行完成的,用了這個回環(huán)柵欄,那么就能讓最后的輸出結(jié)果在線程全部完成之后在進行;
這個效果使用CountDownLatch也可以十分方便的實現(xiàn)
特點總結(jié)
可以看見回環(huán)柵欄可以讓執(zhí)行線程全部等待,到所有線程都完成并調(diào)用await的時候, 柵欄開放,所有的線程一起觸發(fā)之后的流程;
回環(huán)柵欄那么回環(huán)體現(xiàn)在哪里呢?我們可以通過reset方法將它重置,這樣我們就能重新使用它了;關(guān)于reset其中線程的處理可以看reset方法中的處理;