CountDownLatch是在java1.5被引入的,存在於java.util.concurrent包下。CountDownLatch這個類能夠使一個線程等待一定數量(計數器)線程完成各自的工作後再執行後續代碼。例如,應用程序的主線程希望在負責啓動框架服務的線程已經啓動所有的框架服務之後再執行。
CountDownLatch是通過一個計數器來實現的,計數器的初始值爲線程的數量。每當一個線程完成了自己的任務後,計數器的值就會減1。當計數器值到達0時,它表示所有的線程已經完成了任務,然後在閉鎖上等待的線程就可以恢復執行任務。
實例
源碼:
/**
* 線程實現類
*/
public class Worker implements Runnable {
/**
* 線程計數器
*/
private CountDownLatch countDownLatch ;
/**
* 線程睡眠時長
*/
private long timeout;
public Worker(CountDownLatch countDownLatch,long timeout){
this.countDownLatch = countDownLatch;
this.timeout = timeout;
}
@Override
public void run() {
try {//模擬業務操作,睡眠1秒
TimeUnit.SECONDS.sleep(timeout);
System.out.println("線程:" + Thread.currentThread().getName() + "執行完畢!");
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
}
}
/**
* Created by wanghao30 on 2017/9/6.
*/
public class CountDownLatchMain {
//執行線程數
private static int theadNumbers = 10;
public static void main(String[] args) throws InterruptedException {
//創建計數器
CountDownLatch countDownLatch = new CountDownLatch(theadNumbers);
for(int i = 0 ; i < theadNumbers ; i++){
new Thread(new Worker(countDownLatch,i)).start();
}
StringBuilder sb = new StringBuilder();
while (countDownLatch.getCount() > 0){
sb.append("=");
double percent = (double) ((theadNumbers - countDownLatch.getCount()) * 100) / theadNumbers;
System.out.println(sb.toString() + percent + "%");
TimeUnit.MILLISECONDS.sleep(1000);
}
double percent = (double) ((theadNumbers - countDownLatch.getCount()) * 100) / theadNumbers;
System.out.println(sb.toString() + percent + "%");
countDownLatch.await();
System.out.println("-------------------------------------------------------------------------------------");
System.out.println("所有線程執行完畢,主線程繼續執行!");
}
}
輸出
線程:Thread-0執行完畢!
=10.0%
線程:Thread-1執行完畢!
==20.0%
線程:Thread-2執行完畢!
===30.0%
線程:Thread-3執行完畢!
====40.0%
線程:Thread-4執行完畢!
=====50.0%
線程:Thread-5執行完畢!
======60.0%
線程:Thread-6執行完畢!
=======70.0%
線程:Thread-7執行完畢!
========80.0%
線程:Thread-8執行完畢!
=========90.0%
線程:Thread-9執行完畢!
=========100.0%
-------------------------------------------------------------------------------------
所有線程執行完畢,主線程繼續執行!
注意事項
- 構造器中的計數值(count)實際上就是閉鎖需要等待的線程數量。這個值只能被設置一次,而且CountDownLatch沒有提供任何機制去重新設置這個計數值。
- 每個線程必須擁有閉鎖對象
- 在所有線程啓動後,主線程必須使用await()進入等待。
- 線程執行業務結束,調用countDown(),進行計數器操作。
- 使用getCount()可以獲取當前還未執行完成的線程數。
使用場景
- 開始執行前等待n個線程完成各自任務:例如應用程序啓動類要確保在處理用戶請求前,所有N個外部系統已經啓動和運行了。