下面是一個使用 `CountDownLatch` 的案例分析,我們將通過一個簡單的示例來展示如何使用 `CountDownLatch` 來同步多個線程的操作。
### 場景描述
假設我們有一個任務,需要從多個數據源(比如多個數據庫表或文件)中讀取數據,然后進行匯總。為了確保所有數據源的數據都被讀取完成,我們可以使用 `CountDownLatch` 來同步這些操作。
### 步驟
1. **初始化 CountDownLatch**:
? ?設置一個 `CountDownLatch` 對象,其計數器等于需要讀取的數據源數量。
? ?```java
? ?int numberOfDataSources = 3; // 假設有3個數據源
? ?CountDownLatch latch = new CountDownLatch(numberOfDataSources);
? ?```
2. **創建并啟動線程**:
? ?為每個數據源創建一個線程,用于讀取數據。
? ?```java
? ?for (int i = 0; i < numberOfDataSources; i++) {
? ? ? ?new Thread(new DataSourceReader(i, latch)).start();
? ?}
? ?```
3. **定義任務**:
? ?實現 `DataSourceReader` 線程任務,用于從特定數據源讀取數據,并在完成后調用 `countDown()`。
? ?```java
? ?class DataSourceReader implements Runnable {
? ? ? ?private final int dataSourceNumber;
? ? ? ?private final CountDownLatch latch;
? ? ? ?public DataSourceReader(int dataSourceNumber, CountDownLatch latch) {
? ? ? ? ? ?this.dataSourceNumber = dataSourceNumber;
? ? ? ? ? ?this.latch = latch;
? ? ? ?}
? ? ? ?@Override
? ? ? ?public void run() {
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?System.out.println("Reading data from data source " + dataSourceNumber);
? ? ? ? ? ? ? ?// 模擬數據讀取操作
? ? ? ? ? ? ? ?Thread.sleep((long) (Math.random() * 1000));
? ? ? ? ? ? ? ?System.out.println("Data source " + dataSourceNumber + " finished reading.");
? ? ? ? ? ? ? ?latch.countDown(); // 數據讀取完成,減少計數器
? ? ? ? ? ?} catch (InterruptedException e) {
? ? ? ? ? ? ? ?Thread.currentThread().interrupt();
? ? ? ? ? ?}
? ? ? ?}
? ?}
? ?```
4. **等待所有線程完成**:
? ?在主線程中使用 `await()` 方法等待所有數據源的讀取操作完成。
? ?```java
? ?try {
? ? ? ?latch.await(); // 等待所有數據源讀取完成
? ? ? ?System.out.println("All data sources have been read.");
? ? ? ?// 繼續執行匯總操作
? ?} catch (InterruptedException e) {
? ? ? ?Thread.currentThread().interrupt();
? ? ? ?System.out.println("Main thread was interrupted.");
? ?}
? ?```
5. **執行后續操作**:
? ?一旦 `latch.await()` 返回,表示所有數據源的讀取操作已經完成,此時可以安全地執行數據匯總或其他后續操作。
### 分析
在這個案例中,`CountDownLatch` 用于確保主線程在所有數據源的讀取操作完成之前不會繼續執行。這保證了數據的一致性和完整性。每個數據源的讀取線程在完成其任務后通過調用 `countDown()` 來減少 `CountDownLatch` 的計數。當計數達到零時,`await()` 方法返回,主線程可以安全地繼續執行。
這個案例展示了 `CountDownLatch` 在處理需要同步多個線程操作的場景中的實用性,特別是在需要等待多個異步任務完成時。
?