使用Java CountDownLatch实现线程池

在多线程编程中,CountDownLatch 是一个非常有用的工具,它可以让一个或多个线程等待其他线程完成后再继续执行。下面我们将通过一个实例来学习如何结合使用 CountDownLatch 和线程池。

流程概述

我们需要完成的任务是:使用线程池启动多个任务,使用 CountDownLatch 等待所有任务完成。下面的表格展示了整个实现的步骤:

步骤 描述
1 创建线程池
2 初始化 CountDownLatch
3 提交多个任务到线程池
4 等待所有任务完成
5 处理完成后的操作

实现步骤

接下来,我们逐步实现上述步骤。

步骤 1: 创建线程池

我们使用 Executors.newFixedThreadPool 创建一个固定大小的线程池。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

ExecutorService executor = Executors.newFixedThreadPool(5); // 创建一个固定大小为5的线程池

步骤 2: 初始化 CountDownLatch

我们使用 CountDownLatch 来跟踪任务的完成情况。通过传入任务的数量来初始化 CountDownLatch

import java.util.concurrent.CountDownLatch;

int taskCount = 10; // 假设我们有10个任务要执行
CountDownLatch latch = new CountDownLatch(taskCount); // 初始化 CountDownLatch

步骤 3: 提交多个任务到线程池

接下来,我们提交任务到线程池。每个任务在执行时调用 latch.countDown() 来减少计数。

for (int i = 0; i < taskCount; i++) {
    int taskId = i; // 定义任务ID
    executor.submit(() -> {
        try {
            // 模拟任务执行
            System.out.println("Executing task " + taskId);
            Thread.sleep(1000); // 模拟任务耗时
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
        } finally {
            latch.countDown(); // 每个任务完成后调用 countDown
        }
    });
}

步骤 4: 等待所有任务完成

在提交完所有任务后,我们调用 await() 方法,这样就会阻塞主线程,直到所有任务完成。

try {
    latch.await(); // 等待所有任务完成
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // 恢复中断状态
}

步骤 5: 处理完成后的操作

所有任务完成后,可以在这里进行后续处理,例如释放资源或输出结果。

System.out.println("All tasks are completed.");
executor.shutdown(); // 关闭线程池

完整代码示例

将所有步骤整合起来,完整的实现代码如下:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchExample {
    public static void main(String[] args) {
        int taskCount = 10; 
        CountDownLatch latch = new CountDownLatch(taskCount); 
        ExecutorService executor = Executors.newFixedThreadPool(5); 

        for (int i = 0; i < taskCount; i++) {
            int taskId = i; 
            executor.submit(() -> {
                try {
                    System.out.println("Executing task " + taskId);
                    Thread.sleep(1000); 
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    latch.countDown(); 
                }
            });
        }

        try {
            latch.await(); 
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); 
        }

        System.out.println("All tasks are completed.");
        executor.shutdown(); 
    }
}

甘特图

接下来是表示任务流程的甘特图,展示任务的执行过程:

gantt
    title Tasks Execution
    dateFormat  YYYY-MM-DD
    section Tasks
    Execute Task 1    :a1, 2023-10-01, 1d
    Execute Task 2    :a2, 2023-10-01, 1d
    Execute Task 3    :a3, 2023-10-01, 1d
    Execute Task 4    :a4, 2023-10-01, 1d
    Execute Task 5    :a5, 2023-10-01, 1d
    Execute Task 6    :a6, 2023-10-01, 1d
    Execute Task 7    :a7, 2023-10-01, 1d
    Execute Task 8    :a8, 2023-10-01, 1d
    Execute Task 9    :a9, 2023-10-01, 1d
    Execute Task 10   :a10, 2023-10-01, 1d

状态图

以下是任务的状态图,展示任务的执行和完成状态:

stateDiagram
    [*] --> 不可执行
    不可执行 --> 任务执行中: 提交任务
    任务执行中 --> 可执行: 任务完成
    可执行 --> [*]

结尾

通过以上几个步骤,我们成功地使用 CountDownLatch 和线程池实现了一个简单的多线程任务执行模型。希望这篇文章能帮助您更好地理解如何使用 Java 的并发工具,期待您在多线程的路上越走越远!