此次介紹CyclicBarrier:看一眼API的註釋:java
/** * A synchronization aid that allows a set of threads to all wait for * each other to reach a common barrier point. CyclicBarriers are * useful in programs involving a fixed sized party of threads that * must occasionally wait for each other. The barrier is called * <em>cyclic</em> because it can be re-used after the waiting threads * are released.
大概意思:一個讓一組線程同時阻塞到一個位置的同步輔助類。在包含固定線程且線程間必須相互等待的場景中很是有用。cyclic的意思是CyclicBarrier當等待的線程所有釋放以後,能夠重複使用。(英語水平就這樣了。。。。)安全
CyclicBarrier 相似一個閘門,指定數目的線程都必須到達這個閘門,閘門纔會打開。ide
下面使用CyclicBarrier模擬一個門禁系統:線程
需求是這樣的:到放學時間,全部的學生必須刷卡,而後人數齊了自動開門,統一回家。這個需求剛剛的,避免了把部分孩子丟在學校發生危險,特別是幼兒園或者小學生~~get
package com.zhy.concurrency.cyclic; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; /** * 安全的門禁系統 * * @author zhy * */ public class CyclicBarrierTest { /** * 學生總數 */ private final int STUDENT_COUNT = 10; /** * 當人到齊,自動開門程序 */ final CyclicBarrier barrier = new CyclicBarrier(STUDENT_COUNT, new Runnable() { @Override public void run() { System.out.println("人到齊了,開門...."); } }); public void goHome() throws InterruptedException, BrokenBarrierException { System.out.println(Thread.currentThread().getName() + "已刷卡,等待開門回家~"); barrier.await(); System.out.println(Thread.currentThread().getName() + "放學回家~"); } public static void main(String[] args) throws InterruptedException, BrokenBarrierException { final CyclicBarrierTest instance = new CyclicBarrierTest(); /** * 每一個線程表明一個學生 */ for (int i = 0; i < instance.STUDENT_COUNT; i++) { new Thread("學生" + i +" " ) { public void run() { try { instance.goHome(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }; }.start(); } } }
輸出結果:同步
學生1 已刷卡,等待開門回家~ 學生3 已刷卡,等待開門回家~ 學生5 已刷卡,等待開門回家~ 學生9 已刷卡,等待開門回家~ 學生7 已刷卡,等待開門回家~ 學生0 已刷卡,等待開門回家~ 學生2 已刷卡,等待開門回家~ 學生6 已刷卡,等待開門回家~ 學生8 已刷卡,等待開門回家~ 學生4 已刷卡,等待開門回家~ 人到齊了,開門.... 學生4 放學回家~ 學生1 放學回家~ 學生3 放學回家~ 學生5 放學回家~ 學生9 放學回家~ 學生2 放學回家~ 學生6 放學回家~ 學生0 放學回家~ 學生7 放學回家~ 學生8 放學回家~
哈哈,若是哪一個幼兒園用了這麼一套系統,孩子應該不會丟學校了吧,,,,開玩笑了;;it
CyclicBarrier把全部的線程都阻塞在一個閥門位置,而後等到等待的線程數到達預設的值,就打開這個閥門。記得是阻塞線程,不是阻塞操做,在同一個線程使勁掉await是沒什麼效果的。io
上面的例子顯示了CyclicBarrier的基本用法,可是cyclic的功能並無顯示出來,既然註釋中講了,咱們有必要來個例子看看:class
咱們改造下咱們的門禁,畢竟刷卡好不現實,如今需求是這樣的:學生一我的走太危險,如今門衛放學在門口守着,讓學生3個一組的走。thread
package com.zhy.concurrency.cyclic; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; /** * 改造後的門禁系統 * * @author zhy * */ public class CyclicBarrierTest2 { /** * 學生總數 */ private final int STUDENT_COUNT = 12; /** * 每3我的一組出門 */ final CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() { @Override public void run() { System.out.println("有3個學生到齊了,放行...."); } }); public void goHome() throws InterruptedException, BrokenBarrierException { System.out.println(Thread.currentThread().getName() + "已刷卡,等待開門回家~"); barrier.await(); } public static void main(String[] args) throws InterruptedException, BrokenBarrierException { final CyclicBarrierTest2 instance = new CyclicBarrierTest2(); /** * 每一個線程表明一個學生 */ for (int i = 0; i < instance.STUDENT_COUNT; i++) { new Thread("學生" + i +" " ) { public void run() { try { instance.goHome(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }; }.start(); } } }
輸出結果:
學生0 已刷卡,等待開門回家~ 學生1 已刷卡,等待開門回家~ 學生2 已刷卡,等待開門回家~ 有3個學生到齊了,放行.... 學生3 已刷卡,等待開門回家~ 學生5 已刷卡,等待開門回家~ 學生7 已刷卡,等待開門回家~ 有3個學生到齊了,放行.... 學生4 已刷卡,等待開門回家~ 學生9 已刷卡,等待開門回家~ 學生6 已刷卡,等待開門回家~ 有3個學生到齊了,放行.... 學生11 已刷卡,等待開門回家~ 學生10 已刷卡,等待開門回家~ 學生8 已刷卡,等待開門回家~ 有3個學生到齊了,放行....
這個例子充分的體現了CyclicBarrier的複用性,是吧,這樣的系統或許更實在些,0成本~哈哈~。