CompletableFuture、Future、FutureTask
Future
一、是什么?Future
是 Java 5 引入的接口(java.util.concurrent.Future
),代表一个异步计算的结果。它提供了一种检查计算是否完成、等待计算完成以及获取计算结果的方法。
二、解决什么问题
- 阻塞问题:传统同步代码会阻塞主线程等待耗时操作(如网络请求、数据库查询)。
- 结果获取:需要一种机制在耗时操作完成后获取结果,而不阻塞主线程。
- 任务状态跟踪:需要监控异步任务的状态(是否完成、是否取消)。
三、核心方法
java
boolean isDone(); // 检查任务是否完成
V get() throws ...; // 阻塞获取结果(直到完成)
V get(long timeout, TimeUnit unit) throws ...; // 限时阻塞获取
boolean cancel(boolean mayInterrupt); // 尝试取消任务
四、应用场景
- 提交任务到线程池后获取结果
- 并行执行多个独立任务(每个任务一个 Future)
- 设置任务超时时间(避免无限等待)
五、重要注意事项
get()
方法会阻塞调用线程,可能影响性能。- 无法手动设置结果或组合多个任务(如“任务 A 完成后触发任务 B”)。
- 异常处理需在任务内部捕获,无法通过 Future 链式处理。
FutureTask
一、是什么?FutureTask
是 Future 接口的**基础实现类**(
java.util.concurrent.FutureTask),同时实现了
Runnable接口。它既可作为
Future使用,也可作为
Runnable` 提交给线程执行。
二、解决什么问题
- 统一任务封装:将
Callable
/Runnable
任务封装成Runnable
+Future
的结合体。 - 直接线程执行:可直接被
Thread
或线程池执行(因实现了Runnable
)。 - 复用任务对象:同一个任务可被多次执行(需手动重置状态)。
三、核心方法
java
FutureTask(Callable<V> callable); // 构造方法(接受Callable)
FutureTask(Runnable runnable, V result); // 构造方法(接受Runnable)
四、应用场景
- 需要手动创建任务并交给线程执行(而非线程池)
- 将已有
Callable
或Runnable
包装成Future
- 需要复用任务对象(通过重置状态)
五、重要注意事项
- 任务一旦完成,状态不可重置(除非调用
runAndReset()
)。 - 和
Future
一样,get()
会阻塞线程。 - 无法组合多个任务或链式处理结果。
CompletableFuture
一、是什么?CompletableFuture
是 Java 8 引入的类(java.util.concurrent.CompletableFuture
),实现了 Future
接口。它支持非阻塞编程、链式调用和组合异步任务,是函数式异步编程的核心工具。
二、解决什么问题
- 阻塞获取结果:通过回调(如
thenApply()
)避免get()
阻塞。 - 任务组合:轻松实现“任务 A 完成后触发任务 B”或“所有任务完成后合并结果”。
- 异常处理:链式处理异常(
exceptionally()
/handle()
)。 - 手动控制结果:可主动完成任务(
complete()
/completeExceptionally()
)。
三、核心方法
java
static CompletableFuture<Void> runAsync(Runnable runnable); // 无返回任务
static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier); // 有返回任务
// 链式处理
thenApply(Function) // 转换结果
thenAccept(Consumer) // 消费结果
thenRun(Runnable) // 无结果操作
// 组合任务
thenCompose() // 串行组合(A 完成后触发 B)
thenCombine() // 并行组合(A+B 完成后合并结果)
allOf() / anyOf() // 聚合多个任务
// 异常处理
exceptionally() // 捕获异常并返回默认值
handle() // 无论成功/异常都处理
四、应用场景
- 异步流水线处理(如:请求 API → 解析数据 → 保存数据库)
- 合并多个独立异步任务的结果(如:并发查询多个服务)
- 实现超时控制(
orTimeout()
) - 响应式编程(如结合 Spring WebFlux)
五、Java 示例
java
CompletableFuture.supplyAsync(() -> fetchUserFromDB(userId)) // 异步查询
.thenApply(user -> enrichUser(user)) // 转换结果
.thenAccept(user -> saveToCache(user)) // 消费结果
.exceptionally(ex -> { // 异常处理
log.error("Failed", ex);
return null;
})
六、重要注意事项
- 默认使用
ForkJoinPool.commonPool()
,可指定自定义线程池避免资源竞争。 - 避免在回调中阻塞(如调用
get()
),否则失去非阻塞优势。 - 合理处理异常,避免静默失败。
三者核心区别
特性 | Future | Task | CompletableFuture |
---|---|---|---|
是否阻塞 | 是(get() 阻塞) | 是 | 否(支持回调) |
任务组合能力 | ❌ | ❌ | ✅(thenCompose /allOf 等) |
手动设置结果 | ❌ | ❌ | ✅(complete() ) |
异常处理 | 需在任务内部处理 | 需在任务内部处理 | ✅(链式处理) |
函数式支持 | ❌ | ❌ | ✅(Lambda/方法引用) |
Java 版本 | 5+ | 5+ | 8+ |
总结
- Future:基础接口,适用于简单异步任务获取结果,但需阻塞等待。
- FutureTask:
Future
的基础实现,可包装任务并直接交给线程执行。 - CompletableFuture:现代异步编程首选,支持非阻塞、链式调用和任务组合,能优雅处理复杂异步流程。
建议:
- 简单场景用
Future
+ 线程池。- 复杂异步流水线、任务组合用
CompletableFuture
。- 除非特殊需求(如自定义任务状态),否则无需直接使用
FutureTask
。