java併發筆記之--CountDownLatch
知乎 decodelife,轉載請註明出處
本文爲java併發筆記系列之--- CountDownLatch
概念
單詞Latch,中文翻譯是門閂,也就是有“門鎖”的功能,所以當門沒有打開時,N個人是不能進入屋內的,也就是N個線程是不能繼續向下運行的,支持這樣的特性可以控制線程執行任務的時機,使線程以“組團”的方式一起執行任務。
類CountDownLatch也是一個同步功能的輔助類,使用效果是給定一個計數,當使用這個CountDownLatch類的線程判斷計數不爲0時,則呈wait狀態,如果爲0時則繼續運行
使用場景
接下來藉助百米短跑場景進行講解使用場景。
- 首先裁判需要等待所有的運動員到場
- 然後運動員等待裁判發起準備信號
- 裁判等待所有運動員準備就緒,裁判發起起跑信號
- 裁判等待運動員全部跑完
- 裁判宣佈比賽結束
實現代碼如下所示
package com.shunwang.swbox.show.service;
import java.util.concurrent.CountDownLatch;
/**
* 短跑運動員
*
* @author ljs.song
* @date 2017-11-08 19:08
*/
public class RunerPepole extends Thread{
//運動員達起點過程
private CountDownLatch comingTag;
//運動員等待裁判準備信號
private CountDownLatch waitTag;
//運動員等待裁判起跑信號
private CountDownLatch waitRunTag;
//運動員等待裁判說起跑
private CountDownLatch beginTag;
//運動員到達終點
private CountDownLatch endTag;
public RunerPepole(CountDownLatch comingTag, CountDownLatch waitTag, CountDownLatch waitRunTag, CountDownLatch beginTag, CountDownLatch endTag) {
super();
this.comingTag = comingTag;
this.waitTag = waitTag;
this.waitRunTag = waitRunTag;
this.beginTag = beginTag;
this.endTag = endTag;
}
@Override
public void run() {
System.out.println("運動員"+Thread.currentThread().getName() + "正在騎車趕到起點");
try {
Thread.sleep(2000);
System.out.println("運動員"+Thread.currentThread().getName() + "到達起點,等待準備");
comingTag.countDown();
waitTag.await();
System.out.println("運動員"+Thread.currentThread().getName() + "正在準備……");
Thread.sleep(1000);
waitRunTag.countDown();
//等待裁判起跑信號
beginTag.await();
System.out.println("運動員"+Thread.currentThread().getName() + "到達終點******");
endTag.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 裁判端
* @param args
*/
public static void main(String[] args) {
CountDownLatch comintTag = new CountDownLatch(10);
CountDownLatch waitTag = new CountDownLatch(1);
CountDownLatch waitRunTag = new CountDownLatch(10);
CountDownLatch beginTag = new CountDownLatch(1);
CountDownLatch endTag = new CountDownLatch(10);
RunerPepole[] runerPepoles = new RunerPepole[10];
for (int i = 0; i < 10; i++) {
runerPepoles[i] = new RunerPepole(comintTag, waitTag, waitRunTag, beginTag, endTag);
runerPepoles[i].start();
}
try {
System.out.println("裁判等待所有運動員到場");
comintTag.await();
//裁判發起準備信號
System.out.println("裁判發起準備信號");
waitTag.countDown();
System.out.println("裁判檢查等待所有人準備完成");
waitRunTag.await();
System.out.println("裁判發起起跑信號--------------");
beginTag.countDown();
endTag.await();
System.out.println("所有運動員到達終點,比賽結束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
運行結果
運動員Thread-0正在騎車趕到起點
運動員Thread-4正在騎車趕到起點
運動員Thread-2正在騎車趕到起點
運動員Thread-6正在騎車趕到起點
運動員Thread-1正在騎車趕到起點
裁判等待所有運動員到場
運動員Thread-3正在騎車趕到起點
運動員Thread-5正在騎車趕到起點
運動員Thread-7正在騎車趕到起點
運動員Thread-9正在騎車趕到起點
運動員Thread-8正在騎車趕到起點
運動員Thread-1到達起點,等待準備
運動員Thread-5到達起點,等待準備
運動員Thread-9到達起點,等待準備
運動員Thread-4到達起點,等待準備
運動員Thread-8到達起點,等待準備
運動員Thread-0到達起點,等待準備
運動員Thread-3到達起點,等待準備
運動員Thread-6到達起點,等待準備
運動員Thread-2到達起點,等待準備
運動員Thread-7到達起點,等待準備
裁判發起準備信號
裁判檢查等待所有人準備完成
運動員Thread-1正在準備……
運動員Thread-5正在準備……
運動員Thread-9正在準備……
運動員Thread-4正在準備……
運動員Thread-8正在準備……
運動員Thread-0正在準備……
運動員Thread-3正在準備……
運動員Thread-6正在準備……
運動員Thread-2正在準備……
運動員Thread-7正在準備……
裁判發起起跑信號--------------
運動員Thread-1到達終點******
運動員Thread-5到達終點******
運動員Thread-9到達終點******
運動員Thread-4到達終點******
運動員Thread-8到達終點******
運動員Thread-0到達終點******
運動員Thread-7到達終點******
運動員Thread-3到達終點******
運動員Thread-6到達終點******
運動員Thread-2到達終點******
所有運動員到達終點,比賽結束
Process finished with exit code 0
如上結果可以看到,所有的10個運動員在每個節點未拿到信號前,都處於等待(阻塞)狀態,然後拿到信號後,指定數量的運動員(線程)一起開始運行,這樣能達到上述概念中描述的“門鎖”的概念,方便我們工作場景中靈活控制