CompletableFuture详解
一、CompletableFuture简介
CompletableFuture
是Java 8引入的一个类,用于异步编程,它提供了强大的功能来帮助开发者实现非阻塞式的编程,支持函数式风格,并能有效避免回调地狱(Callback Hell)。
核心优势:
- 异步非阻塞:任务可在独立线程中异步执行,不影响主线程。
- 链式调用:支持函数式编程,方便链式处理。
- 组合与聚合:能简单地将多个异步任务结果组合。
- 异常处理:可对异步任务中的异常灵活处理。
二、CompletableFuture创建方式
方式一:手动创建
CompletableFuture<String> future = new CompletableFuture<>();
future.complete("success"); // 手动设置结果
方式二:使用runAsync
(无返回值)
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("异步任务,无返回值");
});
方式三:使用supplyAsync
(有返回值)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "异步任务,有返回值";
});
runAsync
、supplyAsync
方法默认使用公共线程池(ForkJoinPool.commonPool()
)。- 也可指定自定义线程池:
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "使用自定义线程池";
}, executor);
三、获取异步结果
阻塞式获取:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "result");
String result = future.get(); // 会阻塞线程,等待任务执行完毕
非阻塞式获取(推荐):
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "result");
future.thenAccept(result -> {
System.out.println("任务执行完成: " + result);
});
四、CompletableFuture常用方法及用法示例
4.1 链式调用(thenApply、thenAccept、thenRun)
- thenApply(上一步结果作为入参,返回一个新的结果):
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 5)
.thenApply(i -> i * 10); // 结果为50
- thenAccept(消费结果,无返回值):
CompletableFuture.supplyAsync(() -> "Hello")
.thenAccept(System.out::println); // 输出:Hello
- thenRun(不关心上一步结果,无返回值):
CompletableFuture.supplyAsync(() -> "Hello")
.thenRun(() -> System.out.println("任务完成"));
4.2 异常处理(exceptionally、handle)
- exceptionally:捕获异常并提供默认值:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
return 1 / 0; // 模拟异常
}).exceptionally(e -> {
System.out.println("异常: " + e);
return -1; // 默认值
});
- handle:处理结果或异常:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
return 1 / 0; // 模拟异常
}).handle((res, ex) -> {
if (ex != null) {
System.out.println("异常:" + ex);
return -1;
}
return res;
});
4.3 组合多个CompletableFuture任务
thenCompose(任务串行化)
- 将两个有依赖关系的异步任务串联:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 10)
.thenCompose(i -> CompletableFuture.supplyAsync(() -> i + 1)); // 输出11
thenCombine(任务并行组合)
- 两个任务并行执行,结果合并:
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);
CompletableFuture<Integer> combined = future1.thenCombine(future2, (r1, r2) -> r1 + r2);
// combined结果为30
4.4 多个CompletableFuture并发控制
allOf(等待所有任务完成)
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "A");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "B");
CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2);
all.thenRun(() -> {
System.out.println("所有任务执行完毕");
});
anyOf(任意任务完成)
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
Thread.sleep(500);
return "任务1";
});
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
Thread.sleep(100);
return "任务2";
});
CompletableFuture<Object> any = CompletableFuture.anyOf(f1, f2);
any.thenAccept(result -> {
System.out.println("第一个完成的任务结果:" + result);
});
五、常见应用场景
- 提高系统吞吐量(非阻塞式的业务流程)
- 并发调用多个API、远程服务以提升响应速度
- 更优雅地处理异步回调逻辑,减少代码耦合
示例:并发获取数据并聚合
CompletableFuture<String> futureUser = CompletableFuture.supplyAsync(() -> getUser());
CompletableFuture<String> futureOrder = CompletableFuture.supplyAsync(() -> getOrder());
CompletableFuture<String> combined = futureUser.thenCombine(futureOrder, (user, order) -> {
return user + "的订单是:" + order;
});
combined.thenAccept(System.out::println);
六、最佳实践与注意事项
- 避免使用
get()
方法,推荐使用回调方式(如thenAccept、thenApply等); - 使用自定义线程池以避免线程池资源竞争,尤其在高并发场景;
- 合理使用异常处理机制,避免漏掉异步任务异常导致业务流程不正确。
七、总结与推荐
CompletableFuture
是现代Java编程不可缺少的利器,熟练使用它能极大提升代码的并发性能、响应效率和优雅性。尤其在高并发、微服务、异步调用等场景中,熟悉并掌握CompletableFuture
至关重要。