如何实现 Java 线程池等待线程执行完毕再执行主线程

在现代软件开发中,线程池是实现并发编程的重要工具。使用线程池可以提高程序的性能和资源利用率。然而,有时我们需要在主线程中等待线程池中的任务完成后再继续执行。本文将详细介绍如何实现这一过程。

流程概述

在实现“Java线程池等待线程执行完毕再执行主线程”的过程中,我们可以按照以下步骤进行:

步骤 描述
1 创建一个线程池
2 提交任务到线程池
3 等待线程池中的任务完成
4 继续执行主线程

详细步骤

接下来,我们将详细讲解每一步所需的代码和实现。

步骤 1:创建一个线程池

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

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

代码解释:

  • Executors.newFixedThreadPool(4) 创建了一个固定大小为4的线程池,这意味着最多可以同时执行4个任务。

步骤 2:提交任务到线程池

for (int i = 0; i < 10; i++) {
    final int taskId = i;
    executorService.submit(() -> {
        System.out.println("执行任务:" + taskId);
        // 模拟任务执行时间
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

代码解释:

  • executorService.submit(() -> {...}) 提交一个任务到线程池。这里使用了 Lambda 表达式简化代码。
  • Thread.sleep(1000) 模拟任务执行需要的时间。

步骤 3:等待线程池中的任务完成

executorService.shutdown(); // 关闭线程池,不再接受新任务
try {
    // 等待所有任务完成
    if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
        executorService.shutdownNow(); // 超过时间限制则强制关闭
    }
} catch (InterruptedException e) {
    executorService.shutdownNow(); // 在等待期间被中断则强制关闭
}

代码解释:

  • executorService.shutdown() 关闭线程池并不再接受新任务。
  • executorService.awaitTermination(60, TimeUnit.SECONDS) 等待最多60秒,直到所有任务完成。
  • 如果超时(未完成所有任务),则通过 executorService.shutdownNow() 强制关闭线程池。

步骤 4:继续执行主线程

System.out.println("所有任务已完成,主线程继续执行...");

代码解释:

  • 当所有任务完成后,主线程将继续执行后续的代码。

最终代码示例

将以上所有代码结合在一起,完整示例如下:

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

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个固定大小为4的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(4);

        // 提交任务到线程池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executorService.submit(() -> {
                System.out.println("执行任务:" + taskId);
                // 模拟任务执行时间
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        // 等待线程池中的任务完成
        executorService.shutdown(); // 关闭线程池,不再接受新任务
        try {
            // 等待所有任务完成
            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                executorService.shutdownNow(); // 超过时间限制则强制关闭
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow(); // 在等待期间被中断则强制关闭
        }

        // 继续执行主线程
        System.out.println("所有任务已完成,主线程继续执行...");
    }
}

关系图

我们使用 mermaid 创建一个示意图,展示线程池与主线程之间的关系。

erDiagram
    THREAD_POOL {
        String name
        Integer maxThreads
    }

    TASK {
        String taskId
    }

    THREAD_POOL ||--o{ TASK: manages
    TASK }o--|| THREAD_POOL: runs

性能分析

以下是使用 mermaid生成的饼状图,展示了线程池在执行过程中各个任务的完成状态。

pie
    title 任务完成情况
    "已完成的任务": 10
    "未完成的任务": 0

结论

通过上述步骤,我们成功地实现了“在 Java 线程池中等待线程执行完毕再执行主线程”的功能。线程池不仅提高了程序的并发性能,还通过 awaitTermination 方法使得主线程能够优雅地等待其他线程完成。在实际开发中,善加利用这些技术,能够显著提升程序的效率与安全性。希望这篇文章能帮助到刚入行的你,理解并掌握线程池的使用。