同步計數器 CountDownLatch
1. 前言
本節帶領大家認識第二個常用的 Java 并發工具類之 CountDownLatch。
本節先介紹 CountDownLatch 工具類表達的概念和最基本用法,接著通過一個生活中的例子為大家解釋 CountDownLatch 工具類的使用場合,然后通過簡單的編碼實現此場景,最后帶領大家熟悉 CountDownLatch 工具類的其他重要方法。
下面我們正式開始介紹吧。
2. 概念解釋
CountDownLatch 工具類從字面理解為 “倒計數鎖”,其內部使用一個計數器進行實現,計數器初始值為線程的數量。當每一個線程完成自己的任務后,計數器的值就會減一。當計數器的值為 0 時,表示所有的線程都已經完成了任務,然后在 CountDownLatch 上等待的線程就可以恢復繼續執行后繼任務。是不是很抽象,其實很簡單,看下面的圖例。
這就是 CountDownLatch 工具類的基本邏輯。概念已經了解了,CountDownLatch 工具類最基本的用法是怎樣的呢?看下面。
3. 基本用法
// 創建一個 CountDownLatch 對象
CountDownLatch countDownLatch = new CountDownLatch(子線程個數);
// 子線程1開始處理邏輯
...
// 子線程執行完所有邏輯進行計數器減1
countDownLatch.countDown();
// 子線程n開始處理邏輯
...
// 子線程執行完所有邏輯進行計數器減1
countDownLatch.countDown();
// 主線程等待所有子線程執行完
countDownLatch.await();
// 主線程繼續執行后繼邏輯
...
是不是很簡單,CountDownLatch 應用在哪些場合比較合適呢?下面我們給出最常用的場景說明。
4. 常用場景
CountDownLatch 經常用于某一線程在開始運行前等待其他關聯線程執行完畢的場合。
比如我們制作一張復雜報表,報表的各部分可以安排對應的一個線程進行計算,只有當所有線程都執行完畢后,再由最終的報表輸出線程進行報表文件生成。
下面我們使用 CountDownLatch 實現這個例子。假設這張報表有 5 個部分,我們總共安排 5 個子線程分別計算,再設置 1 個報表輸出線程用于最終生成報表文件。請看下面代碼。
5. 場景案例
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
// 創建一個 CountDownLatch 對象,初始化為 5, 代表需要控制同步的子線程個數
static int threadCount = 5;
private static CountDownLatch countDownLatch = new CountDownLatch(threadCount);
// 報表生成主線程
public static void main(String[] args) throws InterruptedException {
// 定義報表子線程
for(int i=1; i<=threadCount; i++) {
// 開始報表子線程處理
new Thread(new Runnable() {
public void run() {
// 模擬報表數據計算時間
try {
Thread.sleep(new Random().nextInt(5000));
} catch (Exception e) {}
System.out.println( Thread.currentThread().getName() + "已經處理完畢");
countDownLatch.countDown();
}
}, "報表子線程" + i).start();
}
// 主線程等待所有子線程運行完畢后輸出報表文件
countDownLatch.await();
System.out.println("報表數據已經全部計算完畢,開始生成報表文件...");
}
}
運行上面代碼,我們觀察一下運行結果。
報表子線程3已經處理完畢
報表子線程5已經處理完畢
報表子線程1已經處理完畢
報表子線程4已經處理完畢
報表子線程2已經處理完畢
報表數據已經全部計算完畢,開始生成報表文件...
觀察結果,和我們的預期一致。注意體會 CountDownLatch 提供的多線程共同協作的模型。
6. 其他方法介紹
除過上面代碼中使用的最基本的 countDown ()、await () 方法之外,還有兩個方法大家可以了解一下。
-
await (long, TimeUnit) 方法
此方法提供了更靈活的等待參數,可以設置等待超時時間。當等待超過了設定的時限,則不再阻塞直接開始后繼處理。 -
getCount () 方法
調用此方法,可獲得當前計數器的數值,了解整體處理進度。
7. 小結
本節解釋了 CountDownLatch 的基本邏輯模型,且通過一個簡單的例子,介紹了 CountDownLatch 的使用場景和基本用法。希望大家在學習過程中,多思考勤練習,早日掌握之。