线程池(newFixedThreadPool)、子线程回应(CountDownLatch)

线程池与CountDownLatch示例
本文介绍如何使用Java线程池newFixedThreadPool及CountDownLatch实现多线程任务管理。通过具体代码示例展示了如何创建固定大小的线程池执行多个任务,并确保所有子线程完成后执行后续操作。
原文地址:[url]http://blog.youkuaiyun.com/conquer0715/article/details/9000548[/url]
利用线程池newFixedThreadPool实现多线程,并通过CountDownLatch实现等待所有子线程结束后执行主线程。

//所有子线程执行完毕后执行主线程
static void threadsCall() {
ExecutorService threadPool = Executors.newFixedThreadPool(10);
int threadTaskNum = 5;
final CountDownLatch answers = new CountDownLatch(threadTaskNum);//同步计数器
for (int i = 0; i < threadTaskNum; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("线程" + Thread.currentThread().getName() + " 开始处理任务 ...");
Thread.sleep((long) (Math.random() * 5000));
System.out.println("线程" + Thread.currentThread().getName() + " 处理完毕,汇报结果!");
answers.countDown();
} catch (Exception e) {}
}
});
}
threadPool.shutdown();// 线程池不再接受新任务,全部任务结束后保证线程池退出运行
try {
answers.await();// 在所有子线程结束前保持阻塞
} catch (InterruptedException e) {}
System.out.println("线程" + Thread.currentThread().getName() + "已收到所有汇报结果");
}
结果:

线程pool-1-thread-1 开始处理任务 ...
线程pool-1-thread-2 开始处理任务 ...
线程pool-1-thread-3 开始处理任务 ...
线程pool-1-thread-4 开始处理任务 ...
线程pool-1-thread-5 开始处理任务 ...
线程pool-1-thread-5 处理完毕,汇报结果!
线程pool-1-thread-2 处理完毕,汇报结果!
线程pool-1-thread-3 处理完毕,汇报结果!
线程pool-1-thread-1 处理完毕,汇报结果!
线程pool-1-thread-4 处理完毕,汇报结果!
线程main已收到所有汇报结果
<think>我们正在讨论Java中如何等待多个异步启动的子线程执行结束。根据引用,有几种常见方法:Thread.join(), CountDownLatch, 以及使用Future和线程池(如ExecutorService)结合。 用户意图明确:需要协调多个子线程执行完毕后再继续主线程。 参考引用: [^1] 提到了使用sleep,但这不是可靠的方法,因为无法精确控制。 [^2] 提到使用Thread.join(),这是基础方法,但需要手动管理每个线程。 [^3] 展示了CountDownLatch的使用,这是更现代的并发工具,可以设置一个计数器,每个线程完成时计数器减一,主线程通过await()等待计数器归零。 [^4] 展示了使用Future和检查所有Future是否完成,并且可以设置超时。 因此,我们主要介绍三种方法: 1. Thread.join() 2. CountDownLatch 3. ExecutorService 配合 Future(或使用CompletableFuture) 此外,我们还可以提到Java 7引入的Fork/Join框架和Java 8的CompletableFuture,但考虑到问题要求等待多个异步启动的子线程,我们重点放在前三种。 注意:异步启动的子线程,意味着这些线程已经通过start()方法启动了。 我们将分别介绍这三种方法,并给出代码示例。 注意:代码示例中,我们使用Runnable来创建线程,实际中也可以使用Callable。 步骤: 1. 使用Thread.join():主线程依次调用每个线程对象的join()方法,这样主线程会阻塞直到该线程结束。 2. 使用CountDownLatch:创建一个CountDownLatch对象,计数初始化为子线程数量。每个子线程结束时调用countDown()。主线程调用await()等待。 3. 使用ExecutorService和Future:将子线程提交给线程池,得到Future对象列表。然后遍历Future列表,调用get()方法(会阻塞直到任务完成)或者使用isDone()检查(但需要循环,如引用[4]所示,但更推荐使用get(),因为get()会阻塞直到完成,或者使用invokeAll)。 但是注意:如果使用ExecutorService,我们通常不会直接使用Thread对象,而是提交任务。如果用户已经用Thread启动了线程,那么就不能再用ExecutorService管理了。因此,我们需要根据用户创建线程的方式来选择。 由于用户提到“异步启动的子线程”,我们假设用户已经通过new Thread().start()启动了多个线程。那么在这种情况下,我们可以使用Thread.join()CountDownLatch,而ExecutorService通常用于通过线程池提交任务的情况。 因此,我们主要展示前两种方法,第三种方法可以作为另一种思路(如果用户愿意改用线程池管理任务)。 下面我们开始组织回答。</think>在 Java 中等待多个异步启动的子线程执行结束,有以下三种常用方法: --- ### 1. **使用 `Thread.join()`(基础方法)** 主线程依次调用每个子线程的 `join()` 方法,阻塞等待所有线程结束。 ```java public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> System.out.println("子线程1完成")); Thread t2 = new Thread(() -> System.out.println("子线程2完成")); t1.start(); // 异步启动 t2.start(); // 异步启动 t1.join(); // 阻塞等待 t1 结束 t2.join(); // 阻塞等待 t2 结束 System.out.println("所有子线程执行完毕,主线程继续"); } ``` **优点**:简单直接。 **缺点**:需手动管理每个线程,扩展性差[^2]。 --- ### 2. **使用 `CountDownLatch`(推荐方法)** 通过计数器实现同步,主线程调用 `await()` 阻塞,子线程完成时调用 `countDown()` 减少计数。 ```java public static void main(String[] args) throws InterruptedException { int threadCount = 3; CountDownLatch latch = new CountDownLatch(threadCount); // 初始化计数器 for (int i = 0; i < threadCount; i++) { new Thread(() -> { try { System.out.println("子线程执行任务..."); Thread.sleep(1000); } finally { latch.countDown(); // 计数器减1 } }).start(); } latch.await(); // 阻塞直到计数器归零 System.out.println("所有子线程执行完毕,主线程继续"); } ``` **优点**:解耦线程管理,支持动态线程数量[^3]。 --- ### 3. **使用 `ExecutorService` 和 `Future`(线程池管理)** 通过线程池提交任务,主线程遍历 `Future` 列表并调用 `get()` 阻塞等待结果。 ```java public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(3); List<Future<?>> futures = new ArrayList<>(); for (int i = 0; i < 3; i++) { futures.add(executor.submit(() -> { System.out.println("子线程执行任务..."); Thread.sleep(1000); return null; })); } // 阻塞等待所有任务完成 for (Future<?> future : futures) { future.get(); // 阻塞直到当前任务完成 } executor.shutdown(); System.out.println("所有子线程执行完毕,主线程继续"); } ``` **优点**:统一管理线程资源,支持返回值[^4]。 --- ### **总结对比** | **方法** | **适用场景** | **扩展性** | **复杂度** | |--------------------|----------------------------------|------------|------------| | `Thread.join()` | 线程数量固定且较少 | 低 | 简单 | | `CountDownLatch` | 动态线程数量,无需返回值 | 高 | 中等 | | `ExecutorService` | 需线程池管理或任务返回值 | 高 | 较高 | > **提示**: > - 若需超时控制,可使用 `latch.await(10, TimeUnit.SECONDS)` 或 `future.get(10, TimeUnit.SECONDS)`[^4]。 > - 避免使用 `Thread.sleep()` 轮询检查(不可靠且浪费资源)[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值