一、Callable 与 Runnable 对比
| 特性 | Runnable | Callable<V> |
|---|
| 返回值 | 无(void) | 有(V 类型) |
| 异常处理 | 不能抛出 checked Exception | 可声明抛出 Exception |
| 函数式接口方法 | run() | call() |
| 适用场景 | 无需返回结果的异步任务 | 需要返回结果 / 异常处理的异步任务 |
二、Future 核心
1. 定义与作用
Future 是对异步任务执行结果的抽象,提供对任务的取消、状态查询、结果获取能力,是 Callable 的 "结果载体"。
2. 核心 API
| 方法 | 功能描述 | 异常说明 |
|---|
boolean cancel(boolean mayInterruptIfRunning) | 取消任务,参数指定是否中断运行中任务 | - |
boolean isCancelled() | 判断任务是否在完成前被取消 | - |
boolean isDone() | 判断任务是否完成(正常终止 / 异常 / 取消均返回 true) | - |
V get() | 阻塞获取结果 | InterruptedException(线程被中断)、ExecutionException(任务执行异常)、CancellationException(任务被取消) |
V get(long timeout, TimeUnit unit) | 超时阻塞获取结果 | 新增 TimeoutException(超时) |
3. FutureTask 实现
4. 应用场景:并行查询商品信息
- 问题:同步查询 5 个接口(各 50ms)需 250ms+
- 解决方案:用 Future 并行执行,总耗时≈最长接口耗时(50ms)
- 代码示例:见原文档
FutureTaskDemo2
5. 局限性
- 结果获取阻塞,无回调机制
- 无法链式调用多个任务
- 不能组合多个任务结果
- 缺乏异常处理机制
三、CompletableFuture 核心(Future 增强版)
1. 核心优势
- 实现 Future 接口,兼容原有功能
- 支持任务编排(串行 / 并行 / 聚合)
- 提供回调机制,非阻塞获取结果
- 内置异常处理
- 支持自定义线程池
2. 异步任务创建(4 个静态方法)
| 方法 | 特点 | 返回值 |
|---|
runAsync(Runnable) | 无返回值,默认线程池 | CompletableFuture<Void> |
runAsync(Runnable, Executor) | 无返回值,自定义线程池 | CompletableFuture<Void> |
supplyAsync(Supplier<U>) | 有返回值,默认线程池 | CompletableFuture |
supplyAsync(Supplier<U>, Executor) | 有返回值,自定义线程池 | CompletableFuture |
注意:默认线程池为ForkJoinPool.commonPool(),建议按业务自定义线程池避免线程饥饿
3. 结果获取方式
| 方法 | 异常处理 | 特点 |
|---|
get() | checked 异常(需捕获 / 抛出) | 阻塞 |
join() | unchecked 异常(无需强制捕获) | 阻塞 |
4. 核心功能分类
(1)结果处理(无返回新结果)
whenComplete(BiConsumer<T, Throwable>):处理正常结果 / 异常exceptionally(Function<Throwable, T>):异常时返回默认值- 示例:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (new Random().nextInt(10) % 2 == 0) {
throw new RuntimeException("测试异常");
}
return "成功";
});
future.whenComplete((result, ex) -> {
System.out.println("结果:" + result + ",异常:" + ex);
}).exceptionally(ex -> {
System.out.println("异常处理:" + ex.getMessage());
return "默认值";
});
(2)结果转换(返回新 CompletableFuture)
| 方法 | 作用 | 区别 |
|---|
thenApply(Function<T, U>) | 转换结果类型 | 同一 CompletableFuture 内转换 |
thenCompose(Function<T, CompletableFuture<U>>) | 依赖任务串联 | 生成新 CompletableFuture,避免嵌套 |
(3)结果消费(无返回值)
| 方法 | 作用 | 适用场景 |
|---|
thenAccept(Consumer<T>) | 消费单个结果 | 单任务结果处理 |
thenAcceptBoth(CompletableFuture<U>, BiConsumer<T, U>) | 消费两个任务结果 | 两个任务都完成后处理 |
thenRun(Runnable) | 不关心结果,执行动作 | 任务完成后触发后续操作 |
(4)任务组合
| 组合类型 | 方法 | 作用 |
|---|
| And 聚合 | thenCombine(CompletableFuture<U>, BiFunction<T, U, V>) | 两个任务完成后合并结果 |
| And 聚合 | runAfterBoth(CompletableFuture<?>, Runnable) | 两个任务完成后执行动作(无返回) |
| Or 聚合 | applyToEither(CompletableFuture<T>, Function<T, U>) | 取先完成任务的结果并转换 |
| Or 聚合 | acceptEither(CompletableFuture<T>, Consumer<T>) | 取先完成任务的结果并消费 |
| Or 聚合 | runAfterEither(CompletableFuture<?>, Runnable) | 任意一个任务完成后执行动作 |
| 多任务 | allOf(CompletableFuture<?>... cfs) | 等待所有任务完成(无返回值) |
| 多任务 | anyOf(CompletableFuture<?>... cfs) | 等待任意一个任务完成(返回该任务结果) |
5. 经典案例:烧水泡茶(最优工序)
// 任务1:洗水壶->烧开水(无返回值)
CompletableFuture<Void> f1 = CompletableFuture.runAsync(() -> {
System.out.println("T1:洗水壶(1s)");
sleep(1);
System.out.println("T1:烧开水(15s)");
sleep(15);
});
// 任务2:洗茶壶->洗茶杯->拿茶叶(有返回值)
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
System.out.println("T2:洗茶壶(1s)");
sleep(1);
System.out.println("T2:洗茶杯(2s)");
sleep(2);
System.out.println("T2:拿茶叶(1s)");
sleep(1);
return "龙井";
});
// 任务3:两个任务完成后泡茶
CompletableFuture<String> f3 = f1.thenCombine(f2, (__, tea) -> {
System.out.println("T1:拿到茶叶" + tea + ",开始泡茶");
return "上茶:" + tea;
});
System.out.println(f3.join()); // 输出:上茶:龙井
四、关键类关系图


五、核心总结
- 技术演进:
Runnable(无返回无异常)→ Callable(有返回有异常)→ Future(结果管理)→ CompletableFuture(任务编排 + 回调) - 核心选择:
- 简单无返回异步任务:Runnable
- 需返回结果 / 异常处理:Callable+Future
- 复杂任务依赖(串行 / 并行 / 聚合):CompletableFuture
- 使用注意事项:
- 避免使用 CompletableFuture 默认线程池,按业务自定义
- 优先使用 join () 而非 get () 简化异常处理
- 复杂任务编排优先使用 CompletableFuture 的回调机制,减少阻塞
所有评论(0)