最近一直整併發這塊東西,順便寫點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個,任務完成!