Java并发编程中的CountDownLatch与CompletableFuture:同步与异步的完美搭档
引言
在Java并发编程中,CountDownLatch
和CompletableFuture
是两个常用于多线程协作的重要工具。它们分别针对不同的场景提供了高效的解决方案:
CountDownLatch
是一个同步工具,用于等待一组线程完成特定操作后再继续执行。CompletableFuture
是一个异步编程框架,支持异步任务的链式调用、结果处理和任务组合。
本文将深入解析这两个工具的核心功能、使用场景以及它们之间的区别,并通过代码示例帮助读者掌握实际应用技巧。
1. CountDownLatch:同步的基石
1.1 核心功能
CountDownLatch
(倒计时门闩)通过一个计数器实现线程同步。
- 初始化:指定一个初始计数值(例如
new CountDownLatch(3)
)。 countDown()
:每调用一次,计数器减1。await()
:阻塞当前线程,直到计数器为0。
1.2 使用场景
- 等待多个线程完成任务:例如主线程需要等待多个子线程完成计算后再汇总结果。
- 资源初始化同步:确保所有资源加载完成后,再启动业务逻辑。
1.3 代码示例
import java.util.concurrent.CountDownLatch;public class CountDownLatchExample {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.currentThread().getName() + " 正在执行任务");Thread.sleep(1000); // 模拟任务耗时} finally {latch.countDown(); // 计数器减1}}).start();}System.out.println("主线程等待所有子线程完成...");latch.await(); // 阻塞直到计数器为0System.out.println("所有子线程已完成,主线程继续执行");}
}
输出结果:
主线程等待所有子线程完成...
Thread-0 正在执行任务
Thread-1 正在执行任务
Thread-2 正在执行任务
所有子线程已完成,主线程继续执行
2. CompletableFuture:异步编程的瑞士军刀
2.1 核心功能
CompletableFuture
是 Java 8 引入的异步编程工具,支持以下特性:
- 异步任务执行:通过
runAsync
或supplyAsync
启动异步任务。 - 链式调用:通过
thenApply
、thenAccept
等方法处理结果或执行后续操作。 - 任务组合:通过
allOf
、anyOf
等方法组合多个异步任务。
2.2 使用场景
- 异步任务链式处理:例如先下载文件,再解析内容,最后保存到数据库。
- 并行任务聚合:同时执行多个独立任务,并等待所有结果。
- 异常处理:通过
exceptionally
或handle
方法捕获异步任务中的异常。
2.3 代码示例
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class CompletableFutureExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {System.out.println("异步任务1执行");}, executor).thenRunAsync(() -> {System.out.println("异步任务2执行");}, executor);future.join(); // 等待所有异步任务完成executor.shutdown();}
}
输出结果:
异步任务1执行
异步任务2执行
3. CountDownLatch vs CompletableFuture
特性 | CountDownLatch | CompletableFuture |
---|---|---|
功能 | 简单的同步工具 | 丰富的异步编程框架 |
使用难度 | 简单 | 复杂(需学习链式调用和组合方法) |
适用场景 | 单纯等待多个线程完成 | 异步任务链式处理、结果组合、异常处理等 |
是否支持结果返回 | 否 | 是(通过 supplyAsync 和回调函数) |
是否支持异常处理 | 否 | 是(通过 exceptionally 或 handle ) |
4. 实际应用建议
4.1 如何选择工具?
使用
CountDownLatch
的场景:- 需要等待一组线程完成任务,但无需获取任务结果。
- 示例:等待多个线程初始化共享资源后,再启动主流程。
使用
CompletableFuture
的场景:- 需要异步执行任务,并处理任务结果或组合多个任务。
- 示例:并行下载多个文件后合并内容,或执行一系列依赖的异步操作。
4.2 结合使用示例
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class HybridExample {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(2);ExecutorService executor = Executors.newFixedThreadPool(2);CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {System.out.println("异步任务1执行");latch.countDown();}, executor);CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {System.out.println("异步任务2执行");latch.countDown();}, executor);latch.await(); // 等待两个异步任务完成System.out.println("所有异步任务已完成");executor.shutdown();}
}
5. 总结
CountDownLatch
是同步工具的代表,适用于简单的线程等待场景。CompletableFuture
是异步编程的利器,支持复杂的任务组合和结果处理。- 在实际开发中,根据需求选择合适的工具:
- 简单同步 →
CountDownLatch
- 异步任务链式处理 →
CompletableFuture
- 简单同步 →
通过合理使用这两个工具,可以显著提升多线程程序的性能和可维护性。无论是构建高并发的服务器,还是优化异步任务流程,它们都是不可或缺的“瑞士军刀”!