【詳解】JUC之CyclicBarrier

引出

柵欄類似於閉鎖,它能阻塞一組線程直到某個事件的發生。柵欄與閉鎖的關鍵區別在於,所有的線程必須同時到達柵欄位置,才能繼續執行。閉鎖用於等待事件,而柵欄用於等待其他線程

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();

    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章