現實生活作中有不少這樣的場景:作F前須要等待A,B,C,D,E完成,A,B,C,D,E能夠併發完成,沒有特定順序,例如:週末在家裏吃飯,有3件事情要作,爸爸作飯,媽媽作菜,兒子收拾餐桌,擺放碗筷。能夠看到這個場景的特徵爲:java
1.在吃飯前有N件事情要作,每件事情都作完後才能吃飯,待處理的事情爲N,每作完一件待處理事情就減小1,當待處理事情爲0時,就能夠吃飯了。編程
2.每件事情能夠並行處理,沒有前後順序,於是提升了效率。緩存
圍繞吃飯,整個過程以下:安全
代碼類結構以下:bash
class EatingActivity implements Runnable {
private CountDownLatch countDownLatch;
public EatingActivity(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
try {
//等待吃飯
System.out.println("Waiting for dinner...");
this.countDownLatch.await();
//全部事情作完後,await被喚醒,開始吃飯
System.out.println("Start eating...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
複製代碼
/** * 作飯 */
class MakeRice implements Runnable {
private CountDownLatch countDownLatch;
public MakeRice(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
exec();
}
/** * 模擬作飯 */
private void exec() {
try {
System.out.println("Start making rice...");
long millis = ((int)(1+Math.random()*(5-1+1))) * 1000;
Thread.sleep(millis);
System.out.println("Making rice is finished.");
//待處理事情減1
this.countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
複製代碼
/** * 作菜 */
class MakeDish implements Runnable {
private CountDownLatch countDownLatch;
public MakeDish(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
exec();
}
/** * 模擬作菜 */
private void exec() {
try {
System.out.println("Start making dish...");
long millis = ((int)(1+Math.random()*(5-1+1))) * 1000;
Thread.sleep(millis);
System.out.println("Making dish is finished.");
//待處理事情減1
this.countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
複製代碼
/** * 收拾桌子 */
class CleanUpTable implements Runnable {
private CountDownLatch countDownLatch;
public CleanUpTable(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
exec();
}
/** * 模擬收拾桌子 */
private void exec() {
try {
System.out.println("Start making rice...");
long millis = ((int)(1+Math.random()*(5-1+1))) * 1000;
Thread.sleep(millis);
System.out.println("Cleaning up table is finished.");
//待處理事情減1
this.countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
複製代碼
/** * @ClassName CountDownLatchTest * @Description 驗證CountDownLatch * @Author 鏗然一葉 * @Date 2019/10/7 22:32 * @Version 1.0 * javashizhan.com **/
public class CountDownLatchTest {
public static void main(String[] args) {
//爲了吃飯,有3件事情要作
CountDownLatch countDownLatch = new CountDownLatch(3);
//吃飯活動
Thread eatingActivity = new Thread(new EatingActivity(countDownLatch));
eatingActivity.start();
//作飯
Thread makeRice = new Thread(new MakeRice(countDownLatch));
//作菜
Thread makeDish = new Thread(new MakeDish(countDownLatch));
//收拾桌子
Thread cleanUpTable = new Thread(new CleanUpTable(countDownLatch));
//並行開始作事情
makeRice.start();
makeDish.start();
cleanUpTable.start();
}
}
複製代碼
輸出日誌:併發
Waiting for dinner...
Start making rice...
Start making rice...
Start making dish...
Cleaning up table is finished.
Making rice is finished.
Making dish is finished.
Start eating...
複製代碼
拼團場景中,滿多少人後就能夠成團,用到了計數器,看起來能夠用CountDownLatch來實現,實際上沒有必要,由於拼團能夠不是並行的,只要有計數器就能夠實現。dom
CountDownLatch的適用場景:工具
1.幾件事情完成以後才能開始另一件事情。post
2.須要作的幾件事情能夠獨立完成,而且能夠並行處理。優化
end.
Java併發編程(一)知識地圖
Java併發編程(二)原子性
Java併發編程(三)可見性
Java併發編程(四)有序性
Java併發編程(五)建立線程方式概覽
Java併發編程入門(六)synchronized用法
Java併發編程入門(七)輕鬆理解wait和notify以及使用場景
Java併發編程入門(八)線程生命週期
Java併發編程入門(九)死鎖和死鎖定位
Java併發編程入門(十)鎖優化
Java併發編程入門(十一)限流場景和Spring限流器實現
Java併發編程入門(十二)生產者和消費者模式-代碼模板
Java併發編程入門(十三)讀寫鎖和緩存模板
Java併發編程入門(十五)CyclicBarrier應用場景
Java併發編程入門(十六)秒懂線程池差異
Java併發編程入門(十七)一圖掌握線程經常使用類和接口
Java併發編程入門(十八)再論線程安全
Java極客站點: javageektour.com/