CyclicBarrier的使用

最近一直整併發這塊東西,順便寫點Java併發的例子,給你們作個分享,也強化下本身記憶,若是有什麼錯誤或者不當的地方,歡迎你們斧正。多線程

CyclicBarrier是一種多線程併發控制實用工具,和CountDownLatch很是相似,它也能夠實現線程間的計數等待,可是它的功能比CountDownLatch更加複雜且強大。CyclicBarrier能夠理解爲循環柵欄,這個計數器能夠反覆使用。好比,假設咱們將計數器設置爲10,那麼湊齊第一批10個線程後,計數器就會歸零,而後接着湊齊下一批10個線程,這就是它的內在含義。併發

LOL和王者榮耀的玩家不少,許多人應該都有打大龍的經歷,話說前期你們打算一塊兒去偷大龍,因爲前期你們都比較弱,須要五我的都齊了才能打大龍,這樣程序該如何實現呢?本人很菜,開始個人代碼是這麼寫的(哈哈你們不要糾結個人時間):dom

public class KillDragon {
    /**
     * 模擬打野去打大龍
     */
   public static void dayePlayDragon(){
       System.out.println("打野在去打大龍的路上,須要10s");
   }

    /**
     * 模擬上單去打大龍
     */
    public static void shangdanPlayDragon(){
        System.out.println("上單在去打大龍的路上,須要10s");
    }

    /**
     * 模擬中單去打大龍
     */
    public static void zhongdanPlayDragon(){
        System.out.println("中單在去打大龍的路上,須要10s");
    }

    /**
     * 模擬ADC和輔助去打大龍
     */
    public static void adcAndFuzhuPlayDragon(){
        System.out.println("ADC和輔助在去打大龍的路上,須要10s");
    }

    /**
     * 模擬你們一塊兒去打大龍
     */
    public static void killDragon()
    {
        System.out.println("打大龍...");
    }

    public static void main(String[] args)
    {
        dayePlayDragon();
        shangdanPlayDragon();
        zhongdanPlayDragon();
        adcAndFuzhuPlayDragon();
        killDragon();
    }

結果以下:ide

打野在去打大龍的路上,須要10s
上單在去打大龍的路上,須要10s
中單在去打大龍的路上,須要10s
ADC和輔助在去打大龍的路上,須要10s
打大龍...

 這完了,你們在路上的時間就花了40s了,顯然是錯誤的。要是都這麼幹,對方把你塔都要偷光了。不行得改進下,怎麼改呢,多線程併發執行,如是我改爲了下面這樣的,用volatile關鍵字。函數

private static volatile int i = 4;
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                long start = System.currentTimeMillis();
                while (i!=0){

                }
                while (i==0) {
                    killDragon();
                    i--;
                    long t = System.currentTimeMillis() - start;
                    System.out.println("總共耗時:"+t+"毫秒");
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                dayePlayDragon();
                try {
                    Thread.sleep(10000);
                    i--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                shangdanPlayDragon();
                try {
                    Thread.sleep(10000);
                    i--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                zhongdanPlayDragon();
                try {
                    Thread.sleep(10000);
                    i--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                adcAndFuzhuPlayDragon();
                try {
                    Thread.sleep(10000);
                    i--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

結果以下:高併發

打野在去打大龍的路上,須要10s
上單在去打大龍的路上,須要10s
中單在去打大龍的路上,須要10s
ADC和輔助在去打大龍的路上,須要10s
打大龍...
總共耗時:10005毫秒

結果彷佛還不錯,可是處理起來實在是有點麻煩,須要 while (i!=0)一直在那循環着。這時候學到了用 CyclicBarrier來處理,代碼以下:工具

public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(5);
        new Thread(new Runnable() {
            @Override
            public void run() {
                long start = System.currentTimeMillis();
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                killDragon();
                long t = System.currentTimeMillis() - start;
                System.out.println("總共耗時:"+t+"毫秒");
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                dayePlayDragon();
                try {
                    Thread.sleep(10000);
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                shangdanPlayDragon();
                try {
                    Thread.sleep(10000);
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                zhongdanPlayDragon();
                try {
                    Thread.sleep(10000);
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                adcAndFuzhuPlayDragon();
                try {
                    Thread.sleep(10000);
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

你們都沒到達以前都等待,結果以下:this

打野在去打大龍的路上,須要10s
上單在去打大龍的路上,須要10s
中單在去打大龍的路上,須要10s
ADC和輔助在去打大龍的路上,須要10s
打大龍...
總共耗時:10002毫秒

CyclicBarrier至關於線程的計數器:線程

CyclicBarrier初始化時規定一個數目,而後計算調用了CyclicBarrier.await()進入等待的線程數。當線程數達到了這個數目時,全部進入等待狀態的線程被喚醒並繼續。
CyclicBarrier就象它名字的意思同樣,可當作是個障礙, 全部的線程必須到齊後才能一塊兒經過這個障礙。
CyclicBarrier初始時還可帶一個Runnable的參數, 此Runnable任務在CyclicBarrier的數目達到後,全部其它線程被喚醒前被執行。
固然這樣使用CyclicBarrier和使用CountDownLatch是沒什麼區別的,正如前文所說的CyclicBarrier的功能更加的複雜且強大。給你們看一個《實戰Java高併發程序設計》一書上的一個例子。
好比:司令下達命令,要求10個士兵去一塊兒完成一項任務。這時,就會要求10個士兵先集合報道,接着,一塊兒雄赳赳氣昂昂地去執行任務。當10個士兵都執行完了任務,那麼司機就能夠對外宣稱,任務完成。相比CountDownLatch,CyclicBarrier能夠接受一個參數做爲BarrierAction。所謂的BarrierAction就是當計數器一次計數完成後,系統會執行的動做。以下構造函數,其中,parties表示技術總數,也就是參與的線程總數。設計

public CyclicBarrier(int parties, Runnable barrierAction)

下面示例演示了上述任務場景

public class CyclicBarrierDemo {
    public static class Soldier implements Runnable {
        private String soldier;
        private final CyclicBarrier cyclicBarrier;

        public Soldier(CyclicBarrier cyclicBarrier, String soldier) {
            this.soldier = soldier;
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                cyclicBarrier.await();
                doWork();
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }

        }

        void doWork() {
            try {
                Thread.sleep(Math.abs(new Random().nextInt() % 10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(soldier + ":任務完成");
        }
    }

    public static class BarrierRun implements Runnable {

        boolean flag;
        int N;

        public BarrierRun(boolean flag, int N) {
            this.flag = flag;
            this.N = N;
        }

        @Override
        public void run() {
            if (flag) {
                System.out.println("司令:[士兵" + N + "個,任務完成!");
            } else {
                System.out.println("司令:[士兵" + N + "個,集合完畢!");
                flag = true;
            }
        }
    }
    
    public static void main(String args[]) {
        final int N = 10;
        Thread[] allSoldier = new Thread[N];
        boolean flag = false;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(N, new BarrierRun(flag, N));
        System.out.println("集合隊伍!");
        for (int i = 0; i < N; i++) {
            System.out.println("士兵" + i + "報道!");
            allSoldier[i] = new Thread(new Soldier(cyclicBarrier, "士兵" + i));
            allSoldier[i].start();
        }
    }
}

執行結果以下:

集合隊伍!
士兵0報道!
士兵1報道!
士兵2報道!
士兵3報道!
士兵4報道!
士兵5報道!
士兵6報道!
士兵7報道!
士兵8報道!
士兵9報道!
司令:[士兵10個,集合完畢!
士兵0:任務完成
士兵2:任務完成
士兵9:任務完成
士兵3:任務完成
士兵7:任務完成
士兵8:任務完成
士兵1:任務完成
士兵4:任務完成
士兵5:任務完成
士兵6:任務完成
司令:[士兵10個,任務完成!
相關文章
相關標籤/搜索