一、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 实现
-
实现关系:
FutureTask implements RunnableFuture extends Runnable, Future -
核心作用:作为 "生产者 - 消费者" 桥梁
- 生产者:执行 Callable 任务,存储结果和状态
- 消费者:通过 Future 接口获取结果 / 状态
-
使用流程:
// 1. 创建Callable任务 Callable<Integer> task = () -> { // 业务逻辑 return 100; }; // 2. 包装为FutureTask FutureTask<Integer> futureTask = new FutureTask<>(task); // 3. 提交执行(线程池/新线程) new Thread(futureTask).start(); // 4. 获取结果(阻塞) Integer result = futureTask.get();
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,避免嵌套 |
-
对比示例:
// thenApply:转换泛型类型 CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "Hello") .thenApply(s -> s + " World"); // thenCompose:串联依赖任务 CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "Hello") .thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));
(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 的回调机制,减少阻塞
