現實生活作中有不少這樣的場景:作F前須要等待A,B,C,D,E完成,A,B,C,D,E能夠併發完成,沒有特定順序,而且F作完後又從新開始,例如:組裝汽車前須要先生產輪胎,車門,車身等等。這個場景的特徵爲:java
1.組裝汽車前有N件事情要作,每件事情都作完後才能組裝汽車。編程
2.每件事情能夠並行處理,沒有前後順序,於是提升了效率。緩存
3.組裝好一輛汽車後繼續生產和組裝下一輛。(固然如今全部零件都是批量生產,不是一個個來的,咱們假設是人工造的限量版賓利,一量量來的。)安全
圍繞造車,整個過程以下:bash
代碼類結構以下:併發
public class MakeCarBody implements Runnable {
private CyclicBarrier cyclicBarrier;
public MakeCarBody(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
public void run() {
exec();
}
/** * 模擬模擬造車身 */
private void exec() {
//造完後繼續造下一個
while(true) {
try {
System.out.println("Start making car body...");
long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000;
TimeUnit.MILLISECONDS.sleep(millis);
System.out.println("Making car body is finished.");
//等待其餘部件造完
this.cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
複製代碼
public class MakeCarDoor implements Runnable {
private CyclicBarrier cyclicBarrier;
public MakeCarDoor(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
public void run() {
exec();
}
/** * 模擬造車門 */
private void exec() {
//造完後繼續造下一個
while(true) {
try {
System.out.println("Start making car door...");
long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000;
TimeUnit.MILLISECONDS.sleep(millis);
System.out.println("Making car door is finished.");
//等待其餘部件造完
this.cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
複製代碼
public class MakeTire implements Runnable {
private CyclicBarrier cyclicBarrier;
public MakeTire(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
public void run() {
exec();
}
/** * 模擬造輪胎 */
private void exec() {
//造完後繼續造下一個
while(true) {
try {
System.out.println("Start making tire...");
long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000;
TimeUnit.MILLISECONDS.sleep(millis);
System.out.println("Making tire is finished.");
//等待其餘部件造完
this.cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
複製代碼
public class AssembleCar implements Runnable {
public void run() {
try {
System.out.println("Start assemble car...");
//模擬組裝汽車
long millis = ((int)(1+Math.random()*(5-1+1))) * 1000;
TimeUnit.MILLISECONDS.sleep(millis);
System.out.println("Making assemble care is finished.");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
複製代碼
public class CyclicBarrierTest {
public static void main(String[] args) {
//有3個部件要造,造完後組裝汽車
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new AssembleCar());
Thread makeCarBody = new Thread(new MakeCarBody(cyclicBarrier));
Thread makeCarDoor = new Thread(new MakeCarDoor(cyclicBarrier));
Thread makeTire = new Thread(new MakeTire(cyclicBarrier));
makeCarBody.start();
makeCarDoor.start();
makeTire.start();
}
}
複製代碼
輸出日誌:dom
Start making car door...
Start making tire...
Start making car body...
Making tire is finished.
Making car door is finished.
Making car body is finished.
Start assemble car...
Making assemble care is finished.
Start making car body...
Start making tire...
Start making car door...
Making car body is finished.
Making tire is finished.
Making car door is finished.
Start assemble car...
Making assemble care is finished.
複製代碼
能夠看到CyclicBarrier的使用方式以下:函數
1.CyclicBarrier的構造函數有2個參數,第1個參數是聲明有幾個部件須要製造(有幾件事能夠並行),第2個參數是一個Runnable,此參數表明並行完以後要作的最後一件事情。工具
2.每一個部件造完後調用CyclicBarrier的await()方法等待啓動下一輪。post
3.當最後一個部件造完後則會自動調用CyclicBarrier構造函數中傳入的Runnable的實現類。
4.Runnable實現類實現完成後從新開始下一輪。
CyclicBarrier的適用場景:
1.幾件事情完成以後才能開始另一件事情。
2.須要作的幾件事情能夠獨立完成,而且能夠並行處理。
3.以上事情完成後繼續下一輪處理。
end.
相關閱讀:
Java併發編程(一)知識地圖
Java併發編程(二)原子性
Java併發編程(三)可見性
Java併發編程(四)有序性
Java併發編程(五)建立線程方式概覽
Java併發編程入門(六)synchronized用法
Java併發編程入門(七)輕鬆理解wait和notify以及使用場景
Java併發編程入門(八)線程生命週期
Java併發編程入門(九)死鎖和死鎖定位
Java併發編程入門(十)鎖優化
Java併發編程入門(十一)限流場景和Spring限流器實現
Java併發編程入門(十二)生產者和消費者模式-代碼模板
Java併發編程入門(十三)讀寫鎖和緩存模板
Java併發編程入門(十四)CountDownLatch應用場景
Java併發編程入門(十六)秒懂線程池差異
Java併發編程入門(十七)一圖掌握線程經常使用類和接口
Java併發編程入門(十八)再論線程安全