在Java的并发编程中,想要优雅地处理多线程任务的结果,Future
和CompletableFuture
是最常见的选择。很多开发者只会基本用法,却对二者的原理与能力了解甚少,导致代码写起来繁琐,性能提升空间受限。那么,这两者究竟有何区别?各自适合哪些场景?本文将系统对比二者原理、功能异同,并配合实际代码实例,帮你真正掌握它们在现代Java开发中的用法精髓。
一、Future概述
1. 简介
Future
接口是Java 5引入的,代表着一个异步任务执行后结果的“占位符”。你可以提交任务,稍后通过Future
对象获取结果或监控状态。
2. 常见方法
get()
:阻塞等待任务完成并返回结果get(timeout, unit)
:带超时时间的阻塞cancel(boolean mayInterruptIfRunning)
:取消任务isDone()
:判断是否已完成isCancelled()
:判断是否已取消
3. 典型用法及代码
import java.util.concurrent.*;
public class FutureDemo {
public static void main(String[] args) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> future = pool.submit(() -> {
Thread.sleep(2000);
return 42;
});
System.out.println("主线程继续干别的...");
// 阻塞等待
Integer result = future.get();
System.out.println("异步计算结果:" + result);
pool.shutdown();
}
}
特点
- 提交任务立即返回Future对象
- 结果需要调用
get()
阻塞等待 - 无法链式编排任务(不支持回调)
- 不能直接组合多个任务
二、CompletableFuture概述
1. 简介
CompletableFuture
是Java 8新增的异步任务增强API,是Future
的升级版。它不仅实现了Future
接口,还扩展了功能,支持丰富的异步编排、流式API、事件回调等。
2. 主要功能
- 非阻塞回调:任务完成后直接触发回调,无需主动get阻塞
- 链式编排:任务可“串行/并行”拼接组合
- 异常处理:内建优雅的异常流转机制
- 支持合并多个Future
- 手动完成、自定义异步线程池
3. 常用静态工厂方法
runAsync(Runnable)
/supplyAsync(Supplier)
:开启一个异步任务thenApply
:对结果进一步处理和转换thenAccept
:消费结果,无返回值thenCombine/thenCompose
:组合两个Futurehandle/exceptionally
:补救异常
4. 基本用法及代码
import java.util.concurrent.*;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(2000); } catch (InterruptedException e) {}
return 42;
});
// 非阻塞式注册回调
cf.thenAccept(result -> System.out.println("回调拿到结果:" + result));
System.out.println("主线程继续执行...");
Thread.sleep(2500); // 等辅助线程执行完
}
}
三、Future与CompletableFuture的区别
特性 | Future | CompletableFuture |
---|---|---|
获取结果 | 需get()阻塞 | 可以同步get,也可异步回调(thenXXX) |
任务编排 | 不支持 | 支持链式、组合、聚合 |
异常处理 | try-catch外显 | handle/exceptionally链式处理 |
取消任务 | 支持 | 支持 |
支持手动赋值 | 不支持 | 支持complete/completeExceptionally等 |
多任务聚合 | 不友好 | allOf/anyOf直接组合 |
线程池 | 需手动提交 | 可指定池,也内置默认ForkJoin |
主动完成 | 不支持 | 支持 |
JDK版本 | JDK5+ | JDK8+ |
四、实战对比与详细代码
1. Future获取异步结果(单一、阻塞方式)
ExecutorService pool = Executors.newCachedThreadPool();
Future<String> future = pool.submit(() -> {
Thread.sleep(1000);
return "Done";
});
String value = future.get(); // 阻塞
System.out.println(value);
pool.shutdown();
2. CompletableFuture 非阻塞回调(链式)
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
try {Thread.sleep(1000);} catch (InterruptedException ignored){}
return "OK";
});
cf.thenApply(s -> s + " - 完成后加工")
.thenAccept(System.out::println); // 非阻塞
Thread.sleep(1500);
3. CompletableFuture 组合多个任务(allOf、anyOf)
CompletableFuture<Integer> one = CompletableFuture.supplyAsync(() -> 1);
CompletableFuture<Integer> two = CompletableFuture.supplyAsync(() -> 2);
CompletableFuture<Void> all = CompletableFuture.allOf(one, two);
all.thenRun(() -> {
try {
int result = one.get() + two.get();
System.out.println("总和:" + result);
} catch (Exception e) {}
});
Thread.sleep(100);
4. CompletableFuture 异常处理
CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(() -> {
if (true) throw new RuntimeException("boom!");
return 100;
}).exceptionally(ex -> {
System.out.println("出异常:" + ex.getMessage());
return -1;
});
System.out.println("最终结果:" + cf.get());
五、应用场景最佳实践
-
Future适用场景:
- 简单异步,偶尔要等待结果
- 并发量不大,业务逻辑清晰
- 硬性依赖结果后再后续处理(但只能同步阻塞等待)
-
CompletableFuture适用场景:
- 流式复杂任务编排、聚合
- 高并发、异步化、非阻塞服务端开发(如异步微服务调用)
- 多任务一起跑,快速返回或异常自动补偿
- 回调式业务通知、事件驱动设计
六、总结
Future 和 CompletableFuture 都是Java异步编程的重要工具。Future简单但能力有限,逐渐成为“历史遗留”;CompletableFuture支持更丰富的异步、组合、异常链式处理,是现代异步任务与响应式编排的首选。