Future与CompletableFuture:异步编程对比
一、什么是 Future?
✅ 概念:
Future
是 Java 中用于表示异步计算结果的接口。当我们使用线程池执行一个任务时(比如 ExecutorService.submit(Callable)
),它会返回一个 Future
对象,我们可以通过这个对象来:
- 判断任务是否完成
- 获取任务的结果
- 取消任务
⚠️ 注意:
调用 get()
方法获取结果时,如果任务还没完成,线程会被阻塞直到任务完成。
💡 示例代码:
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Integer> future = executor.submit(() -> {// 模拟耗时操作Thread.sleep(1000);return 42;
});System.out.println("任务是否完成?" + future.isDone());
Integer result = future.get(); // 阻塞等待结果
System.out.println("任务结果:" + result);
📌 适用场景:
- 简单的异步任务执行,只需要获取一次结果。
- 不需要链式处理或组合多个异步任务。
- 不太关心任务之间的依赖关系。
二、什么是 CompletableFuture?
✅ 概念:
CompletableFuture
是 Java 8 引入的一个更强大的异步编程工具,它是 Future
的增强版。除了可以像 Future
一样获取异步结果外,还支持:
- 异步回调(任务完成后自动触发下一步)
- 组合多个异步任务(串行、并行、聚合等)
- 异常处理
- 手动完成任务
你可以把它看作是一个“可编程的 Future”。
💡 示例代码:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {// 异步任务return "Hello";
}).thenApply(s -> s + " World").thenApply(String::toUpperCase);future.thenAccept(System.out::println); // 输出: HELLO WORLD
📌 适用场景:
- 需要多个异步任务之间有前后依赖关系
- 需要组合多个异步结果(如合并两个请求的结果)
- 需要优雅地处理异常
- 实现类似 Node.js 或 RxJava 的链式异步编程风格
三、Future vs CompletableFuture:主要区别
特性 | Future | CompletableFuture |
---|---|---|
是否能手动完成任务 | ❌ 否 | ✅ 是 |
是否支持回调 | ❌ 否 | ✅ 是 |
是否支持链式调用 | ❌ 否 | ✅ 是 |
是否支持组合多个任务 | ❌ 否 | ✅ 是 |
是否支持异常处理 | ❌ 否 | ✅ 是 |
使用复杂度 | 简单 | 相对复杂 |
四、常见用法总结
✅ Future 的常用方法:
boolean isDone()
:判断任务是否完成V get()
:获取任务结果(阻塞)boolean cancel(boolean mayInterruptIfRunning)
:取消任务boolean isCancelled()
:任务是否被取消
✅ CompletableFuture 的常用方法:
supplyAsync(Supplier<T>)
:异步执行有返回值的任务runAsync(Runnable)
:异步执行无返回值的任务thenApply(Function<T, R>)
:对结果做转换thenAccept(Consumer<T>)
:消费结果但不返回新值thenRun(Runnable)
:任务完成后执行后续动作thenCombine(CompletableFuture<T>, BiFunction<T, U, R>)
:组合两个异步结果exceptionally(Function<Throwable, ? extends T>)
:处理异常
五、总结一句话:
如果你只是想提交一个任务然后等待它的结果,用
Future
就够了;
如果你需要异步流程编排、链式调用、结果组合、错误处理,那一定要用CompletableFuture
!
如果你已经掌握了 Callable
, Runnable
, ExecutorService
等基础内容,那么接下来就建议你动手写几个 CompletableFuture
的例子,体会一下什么叫真正的“异步编程”!