一、概述
CountDownLatch是什麼?網上概念的描述太多了。其實個人理解,他就是--等待多線程計數器!
即:在某線程中(主線程或其他分線程都可以)聲明一個初始值爲N的CountDownLatch計數器,然後等待多個子線程完成了相關操作後再繼續向下執行。--當各子線程執行到相應的地方後使N-1,最後N=0時,線程不再等待,繼續向下執行。
二、運用及場景
2.1、運用
- CountDownLatch latch = new CountDownLatch(N); //構造對象時候 需要傳入參數N 即計數器值
- latch.await();//能夠阻塞線程 直到調用N次latch.countDown() 方法才釋放線程
- latch.countDown();//在多個子線程中調用 每次調用,N計數器值-1
2.2、場景
需要等待其他線程做完某動作後再繼續執行後續操作(當前線程多異步操作完成後再向下執行)--或等待超時後繼續執行。
例:每天0點同時備份前一天的數據表,即0點開啓與備份表相同的線程數分別同時備份表,全部成功後返回true,失敗後返回false
三、案例解析
3.1、描述一個案例:3個人在等公交,公交停下後,分別上車,找到座位後車才啓動。
先創建一個值爲3(nameList.length)的CountDownLatch計數器 → 啓動3個子線程分別執行任務(之後,主線程陷入等待latch.await()) → 子線程執行後將計數器-1(latch.countDown()) → 計數器值爲0後喚醒主線程繼續向下執行
public static void main(String[] args) {
try {
Random random = new Random();//生成隨機數類
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設置日期格式
System.out.println("現在是北京時間:"+df.format(new Date())+"======>公交車停車了!");
String[] nameList = new String[]{"張三","李四","王五"};//假設此爲在公交站臺排隊的人
CountDownLatch latch = new CountDownLatch(nameList.length);//聲明一個與人數相等的計數器
for(String name : nameList){
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(name+"小老弟,上車了!===》"+df.format(new Date()));
int s = random.nextInt(6);//生成0-6的隨機數,用做等待秒數
System.out.println(name+"小老弟,找座位需要===》"+s+"秒!");
Thread.sleep(s*1000);//等待s秒
System.out.println(name+"小老弟,找到座位了!===》"+df.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
} finally {
latch.countDown();//計數器-1
}
}
}).start();
}
latch.await();//等待
System.out.println("現在是北京時間:"+df.format(new Date())+"======>公交車啓動了!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
結果:
3.2、描述一個案例:3個人在等公交,公交停下後分別上車,待2人找到位置後,或2秒之後,公交啓動。
先創建一個值爲2的CountDownLatch計數器 → 啓動3個子線程分別執行任務(之後,主線程陷入等待latch.await(2, TimeUnit.SECONDS),超時時間設置爲2秒) → 子線程執行後將計數器-1(latch.countDown()) → 計數器值爲0、或等待超時後 喚醒主線程繼續向下執行
public static void main(String[] args) {
try {
Random random = new Random();//生成隨機數類
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設置日期格式
System.out.println("現在是北京時間:"+df.format(new Date())+"======>公交車停車了!");
String[] nameList = new String[]{"張三","李四","王五"};//假設此爲在公交站臺排隊的人
CountDownLatch latch = new CountDownLatch(2);//聲明一個與人數相等的計數器
for(String name : nameList){
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(name+"小老弟,上車了!===》"+df.format(new Date()));
int s = random.nextInt(6);//生成0-6的隨機數,用做等待秒數
System.out.println(name+"小老弟,找座位需要===》"+s+"秒!");
Thread.sleep(s*1000);//等待s秒
System.out.println(name+"小老弟,找到座位了!===》"+df.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
} finally {
latch.countDown();//計數器-1
}
}
}).start();
}
latch.await(2, TimeUnit.SECONDS);//等待計數器爲0,或2秒
System.out.println("現在是北京時間:"+df.format(new Date())+"======>公交車啓動了!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
結果:
可能性1:
可能性2: