2.2 CyclicBarrier的理解和使用

快速理解:給所有線程加上了一個屏障,只有所有的線程都到達屏障之後(即cyclicbarrier初始值count=0),所有線程纔會繼續執行

CyclicBarrier的簡單使用:初始cyclicBarrier是3,當三個線程都到達 屏障(即執行await())之後,三個線程才能夠自動執行

常用方法:下面都有使用示例

1、static CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

2、static CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new CountSum());

3、cyclicBarrier.await();

最簡單的示例:(沒看資料之前自己憑理解完成的小demo,下面會有實際使用的例子)

 

public class MyCyclicBarrier {
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

    public static void main(String[] args) {
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"開始運行");
                System.out.println(Thread.currentThread().getName()+"到達屏障");
                Thread.sleep(1000);
                cyclicBarrier.await();

                System.out.println(Thread.currentThread().getName()+"所有線程到達屏障,"+ Thread.currentThread().getName()+"開始執行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"開始運行");
                System.out.println(Thread.currentThread().getName()+"到達屏障");
                Thread.sleep(500);
                cyclicBarrier.await();

                System.out.println(Thread.currentThread().getName()+"所有線程到達屏障,"+ Thread.currentThread().getName()+"開始執行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"開始運行");
                System.out.println(Thread.currentThread().getName()+"到達屏障");
                Thread.sleep(100);
                cyclicBarrier.await();

                System.out.println(Thread.currentThread().getName()+"所有線程到達屏障,"+ Thread.currentThread().getName()+"開始執行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();
    }

}

執行結果:三個線程分別sleep時間不同,來模擬不同線程處理不同的任務,結果三個線程都執行await之後,三個線程才能能夠繼續執行

Thread-0開始運行
Thread-0到達屏障
Thread-1開始運行
Thread-1到達屏障
Thread-2開始運行
Thread-2到達屏障
Thread-0所有線程到達屏障,Thread-0開始執行
Thread-2所有線程到達屏障,Thread-2開始執行
Thread-1所有線程到達屏障,Thread-1開始執行

第二個小栗子:證明CyclicBarrier可以多次重複使用

 

public class MyCyclicBarrier {
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

    public static void main(String[] args) {
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"開始運行第一個任務");
                System.out.println(Thread.currentThread().getName()+"到達屏障");
                Thread.sleep(1000);
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName()+"所有線程到達第一道屏障,"+ Thread.currentThread().getName()+"開始執行");
                System.out.println(Thread.currentThread().getName()+"開始執行第二個任務");
                Thread.sleep(1000);
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName()+"所有線程到達第二道屏障,"+ Thread.currentThread().getName()+"開始執行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"開始運行第一個任務");
                System.out.println(Thread.currentThread().getName()+"到達屏障");
                Thread.sleep(500);
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName()+"所有線程到達第一道屏障,"+ Thread.currentThread().getName()+"開始執行");
                System.out.println(Thread.currentThread().getName()+"開始執行第二個任務");
                Thread.sleep(500);
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName()+"所有線程到達第二道屏障,"+ Thread.currentThread().getName()+"開始執行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"開始運行第一個任務");
                System.out.println(Thread.currentThread().getName()+"到達屏障");
                Thread.sleep(100);
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName()+"所有線程到達第一道屏障,"+ Thread.currentThread().getName()+"開始執行");
                System.out.println(Thread.currentThread().getName()+"開始執行第二個任務");
                Thread.sleep(100);
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName()+"所有線程到達第二道屏障,"+ Thread.currentThread().getName()+"開始執行");

            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();
    }

}

運行結果:證明CyclicBarrier可以多次重複使用

Thread-0開始運行第一個任務
Thread-0到達屏障
Thread-1開始運行第一個任務
Thread-1到達屏障
Thread-2開始運行第一個任務
Thread-2到達屏障
Thread-0所有線程到達第一道屏障,Thread-0開始執行
Thread-0開始執行第二個任務
Thread-1所有線程到達第一道屏障,Thread-1開始執行
Thread-1開始執行第二個任務
Thread-2所有線程到達第一道屏障,Thread-2開始執行
Thread-2開始執行第二個任務
Thread-2所有線程到達第二道屏障,Thread-2開始執行

 

到達CyclicBarrier屏障時,設置優先執行的線程CyclicBarrier(int parties,Runnable barrierAction),從而對多個線程的計算結果彙總

代碼示例:

public class MyCyclicBarrierCount {
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new CountSum());
    static ConcurrentHashMap<Long, Integer> hashMap = new ConcurrentHashMap<>(3);

    static class CountAdd extends Thread {
        int start;
        int end;

        public CountAdd(int start, int end) {
            this.start = start;
            this.end = end;
        }

        @Override
        public void run() {
            int sum = 0;
            for (int i = start; i <= end; i++) {
                sum = sum + i;
            }
            hashMap.put(Thread.currentThread().getId(), sum);
            System.out.println(Thread.currentThread().getName()+"計算完成了從"+start+"到"+end+"之和:"+sum);
            try {
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"線程到達屏障,繼續執行,但是會在CountSum()執行完成之後纔開始執行");
        }
    }

    static class CountSum extends Thread {

        @Override
        public void run() {
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+"CountSum()執行完成之後,其他到達屏障的線程纔會繼續執行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int sum = 0;
            Set<Map.Entry<Long, Integer>> entries = hashMap.entrySet();
            for (Map.Entry<Long, Integer> entry : entries) {
                sum += entry.getValue();

            }
            System.out.println("從1加到100的總數是:" + sum);
        }
    }

    public static void main(String[] args) {
        new CountAdd(1,20).start();
        new CountAdd(21,60).start();
        new CountAdd(61,100).start();
    }

}

結果:計算結果之後,立馬會執行static CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new CountSum());中的CountSum()線程

完全執行完成之後,其他到達屏障的線程纔會繼續執行

Thread-1計算完成了從1到20之和:210
Thread-3計算完成了從61到100之和:3220
Thread-2計算完成了從21到60之和:1620
Thread-2CountSum()執行完成之後,其他到達屏障的線程纔會繼續執行
從1加到100的總數是:5050
Thread-2線程到達屏障,繼續執行,但是會在CountSum()執行完成之後纔開始執行
Thread-1線程到達屏障,繼續執行,但是會在CountSum()執行完成之後纔開始執行
Thread-3線程到達屏障,繼續執行,但是會在CountSum()執行完成之後纔開始執行

 

 

 

 

 

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