引出
柵欄類似於閉鎖,它能阻塞一組線程直到某個事件的發生。柵欄與閉鎖的關鍵區別在於,所有的線程必須同時到達柵欄位置,才能繼續執行。閉鎖用於等待事件,而柵欄用於等待其他線程。
CyclicBarrier可以使一定數量的線程反覆地在柵欄位置處彙集。當線程到達柵欄位置時將調用await方法,這個方法將阻塞直到所有線程都到達柵欄位置。 如果所有線程都到達柵欄位置,那麼柵欄將打開,此時所有的線程都將被釋放,而柵欄將被重置以便下次使用。
舉個例子,就像生活中我們會約朋友們到某個餐廳一起吃飯,有些朋友可能會早到,有些朋友可能會晚到,但是這個餐廳規定必須等到所有人到齊之後纔會讓我們進去。這裏的朋友們就是各個線程,餐廳就是 CyclicBarrier。
API使用
構造方法
public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
parties
是參與線程的個數- 第二個構造方法有一個
Runnable
參數,這個參數的意思是最後一個到達線程要做的任務
重要方法
public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
- 線程調用 await() 表示自己已經到達柵欄
- BrokenBarrierException 表示柵欄已經被破壞,破壞的原因可能是其中一個線程 await() 時被中斷或者超時
其他方法
public void reset()
- 將屏障重置爲初始狀態。 如果任何一方正在等待屏障,他們將返回BrokenBarrierException 。
- 這樣就可以重複利用這個屏障
CyclicBarrier 與 CountDownLatch 區別
CountDownLatch
是一次性的。CyclicBarrier
是可循環利用的CountDownLatch
參與的線程的職責是不一樣的,有的在倒計時,有的在等待倒計時結束。CyclicBarrier
參與的線程職責是一樣的
利用CountDownLatch實現回調函數
實現:
- 在每個線程使計數器減一的時候,利用getCount判斷,當前是否所有線程任務執行完成
public class CyclicBarrierTest {
static class MyCountDownLatch extends CountDownLatch{
private final Runnable runnable;
public MyCountDownLatch(int count,Runnable runnable) {
super(count);
this.runnable = runnable;
}
@Override
public void countDown() {
super.countDown();
if (getCount()==0){
this.runnable.run();
}
}
}
public static void main(String[] args) {
final MyCountDownLatch latch = new MyCountDownLatch(2, ()->{
System.out.println("All of work finish done. This is call back.");
});
new Thread(){
@Override
public void run() {
try {
Thread.sleep(1000);
latch.countDown();
System.out.println(getName() + " finished.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
@Override
public void run() {
try {
Thread.sleep(1000);
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + " finished.");
}
}.start();
}
}