
Java子线程如何优雅地通知主线程任务完成?
高效的多线程编程需要子线程在任务完成后通知主线程。本文介绍两种常用的方法:CompletableFuture 和 CountDownLatch,并着重强调线程安全和最佳实践。
方法一:使用 CompletableFuture
CompletableFuture 提供了一种简洁的方式来处理异步操作,并方便地等待多个子线程完成。CompletableFuture.allOf() 方法可以等待所有给定的 CompletableFuture 对象完成。
立即学习“Java免费学习笔记(深入)”;
代码示例:
iWebMall 是一款高性能高扩展能力的开源 LAMP 电子商务软件,定位为大中型电子商务平台软件,服务于有建立电子商务需求的商业客户。这些商业客户不必学习任何计算机编程代码知识,只需要使用 iWebMall 软件他们就可以轻松建立一个功能强大的网上商城,实现用户注册、产品展示、在线定购、在线支付等电子商务功能;iWebMall 集成了产品发布与查询、会员注册登录、购物车、在线订单、在线支付、在
List> futures = new ArrayList<>(); // 创建并启动子线程 for (int i = 0; i < 2; i++) { futures.add(CompletableFuture.runAsync(() -> { // 模拟子线程任务 System.out.println("子线程 " + i + " 执行完成"); })); } // 等待所有子线程完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // 主线程处理数据 System.out.println("所有子线程执行完成,开始处理数据"); }
方法二:使用 CountDownLatch
CountDownLatch 是一种同步工具类,可以用来等待一组事件的完成。初始化时设置计数器,每个子线程完成任务后调用 countDown() 方法将计数器减一,主线程调用 await() 方法等待计数器变为零。
代码示例:
final CountDownLatch latch = new CountDownLatch(2); // 初始化计数器为 2
// 创建并启动子线程
for (int i = 0; i < 2; i++) {
new Thread(() -> {
// 模拟子线程任务
System.out.println("子线程 " + i + " 执行完成");
latch.countDown(); // 计数器减 1
}).start();
}
// 主线程等待子线程完成
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 主线程处理数据
System.out.println("所有子线程执行完成,开始处理数据");
}
重要提示:
-
线程安全:
ArrayList不是线程安全的。在并发环境下,建议使用CopyOnWriteArrayList来替代,以避免数据竞争。 如果需要在子线程中修改共享变量,则必须使用合适的同步机制,例如volatile关键字或锁机制,以确保线程安全。 -
异常处理: 在实际应用中,需要完善的异常处理机制,以捕获并处理子线程中可能发生的异常。
CompletableFuture提供了exceptionally()方法来处理异常。CountDownLatch需要在await()方法中捕获InterruptedException。
选择哪种方法取决于具体的应用场景。CompletableFuture 更适用于需要处理异步结果的情况,而 CountDownLatch 更适用于简单的等待多个线程完成的情况。 记住始终优先考虑线程安全和健壮的异常处理。









