下面是一个使用 `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` 在处理需要同步多个线程操作的场景中的实用性,特别是在需要等待多个异步任务完成时。