FutureTask 是 JDK 1.5 引入的,核心用于获取异步任务结果,它实现了 Future 和 Runnable 接口,主要解决「任务异步执行 + 结果后续获取」的基础需求。
get() 方法阻塞获取结果、cancel() 方法取消任务;ExecutorService 执行(或直接 new 后手动 start),本身不提供线程池管理。当你只需要执行一个独立的异步任务,且后续需要拿到任务结果(比如计算一个复杂值、调用一个耗时接口),此时 FutureTask 足够简洁高效。
示例: 后台计算一个大数据量的统计值,主线程后续需要用这个结果展示报表。
// 1. 定义任务(实现 Callable)
Callable<Integer> calculateTask = () -> {
// 模拟耗时计算
Thread.sleep(3000);
return 1000; // 任务结果
};
// 2. 包装为 FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(calculateTask);
// 3. 提交到线程池执行
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(futureTask);
// 4. 主线程做其他事(非阻塞)
System.out.println("主线程处理其他逻辑...");
// 5. 后续需要结果时,阻塞获取(或用 isDone() 轮询)
try {
Integer result = futureTask.get(); // 阻塞直到任务完成
System.out.println("任务结果:" + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
FutureTask 的 cancel(boolean mayInterruptIfRunning) 方法支持取消任务:
mayInterruptIfRunning=true:如果任务已启动且正在运行,尝试中断线程(需任务内部响应中断,比如检查 Thread.interrupted());mayInterruptIfRunning=false:仅取消未启动的任务。示例:
用户发起一个异步查询,后来主动取消,此时可调用 futureTask.cancel(true) 终止任务,避免资源浪费。
CompletableFuture 是 JDK 1.8 引入的,若项目仍在使用 JDK 1.7 及以下,FutureTask 是实现异步结果获取的主要选择。
CompletableFuture 是 JDK 1.8 基于「响应式编程」思想设计的,核心解决「多任务依赖编排、异步回调、结果组合」等复杂场景,是 FutureTask 的超集。
thenApply/thenAccept/thenRun 等),轻松编排多任务依赖;allOf/anyOf),处理并行任务集合;exceptionally/handle),统一捕获上下游异常;supplyAsync/runAsync 静态方法,直接结合 ForkJoinPool 执行,无需手动创建线程池(也可指定自定义线程池);当多个任务存在「先后依赖」(比如:任务A的结果是任务B的输入,任务B的结果是任务C的输入),CompletableFuture 的链式调用可避免嵌套,代码更清晰。
示例: 用户注册流程:① 保存用户信息(任务A)→ ② 生成用户ID → ③ 发送欢迎短信(任务B,依赖用户ID)→ ④ 记录操作日志(任务C,依赖短信发送结果)。
// 自定义线程池(推荐,避免使用默认 ForkJoinPool)
ExecutorService userPool = Executors.newFixedThreadPool(3);
ExecutorService msgPool = Executors.newSingleThreadExecutor();
// 任务A:保存用户信息(返回用户ID)
CompletableFuture<Long> saveUserFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("任务A:保存用户信息");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 1001L; // 用户ID
}, userPool);
// 任务B:发送欢迎短信(依赖任务A的用户ID,返回短信发送状态)
CompletableFuture<Boolean> sendMsgFuture = saveUserFuture.thenApplyAsync(userId -> {
System.out.println("任务B:给用户 " + userId + " 发送短信");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return true; // 短信发送成功
}, msgPool);
// 任务C:记录操作日志(依赖任务B的短信状态,无返回值)
CompletableFuture<Void> logFuture = sendMsgFuture.thenAcceptAsync(success -> {
System.out.println("任务C:记录短信发送日志,状态:" + success);
}, userPool);
// 等待所有任务完成(可选,若主线程需等待流程结束)
logFuture.join();
// 关闭线程池
userPool.shutdown();
msgPool.shutdown();
当需要同时执行多个独立任务,且需:
allOf);anyOf);示例1:等待所有任务完成 并行调用3个不同的接口,全部完成后才继续后续逻辑:
// 任务1:获取用户基础信息
CompletableFuture<User> userFuture = CompletableFuture.supplyAsync(() -> userService.getUser(1001));
// 任务2:获取用户订单列表
CompletableFuture<List<Order>> orderFuture = CompletableFuture.supplyAsync(() -> orderService.getOrders(1001));
// 任务3:获取用户优惠券
CompletableFuture<List<Coupon>> couponFuture = CompletableFuture.supplyAsync(() -> couponService.getCoupons(1001));
// 等待所有任务完成(无返回值,仅等待)
CompletableFuture<Void> allFuture = CompletableFuture.allOf(userFuture, orderFuture, couponFuture);
// 后续逻辑需在所有任务完成后执行
allFuture.thenRun(() -> {
try {
User user = userFuture.get();
List<Order> orders = orderFuture.get();
List<Coupon> coupons = couponFuture.get();
// 合并数据并返回给前端
System.out.println("用户信息:" + user + ",订单数:" + orders.size() + ",优惠券数:" + coupons.size());
} catch (Exception e) {
e.printStackTrace();
}
}).join();
示例2:获取任意一个任务完成的结果 并行调用多个支付渠道,哪个渠道先返回结果就用哪个:
// 任务1:调用支付宝支付
CompletableFuture<String> aliPayFuture = CompletableFuture.supplyAsync(() -> aliPayService.pay(100.0));
// 任务2:调用微信支付
CompletableFuture<String> wxPayFuture = CompletableFuture.supplyAsync(() -> wxPayService.pay(100.0));
// 等待任意一个任务完成(返回最先完成的任务结果)
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(aliPayFuture, wxPayFuture);
// 处理最先完成的结果
anyFuture.thenAccept(result -> {
System.out.println("支付成功,渠道返回:" + result);
}).join();
当任务执行完成后,需要触发后续操作(比如:异步生成报表后,自动发送邮件通知),且主线程无需等待,此时 CompletableFuture 的回调机制可避免阻塞,提升系统吞吐量。
示例: 用户提交报表生成请求后,主线程直接返回“报表正在生成中”,报表生成完成后异步发送邮件通知用户:
// 任务1:生成报表(耗时操作)
CompletableFuture<Report> reportFuture = CompletableFuture.supplyAsync(() -> reportService.generateReport(1001));
// 任务2:报表生成完成后,发送邮件(回调任务)
reportFuture.thenAcceptAsync(report -> {
System.out.println("报表生成完成,开始发送邮件...");
emailService.sendEmail(report.getUserId(), "报表已生成", report.getDownloadUrl());
}, emailExecutor);
// 主线程直接返回响应,无需等待报表生成和邮件发送
System.out.println("报表正在生成中,请稍后查看邮件通知...");
CompletableFuture 支持链式异常处理,可在任务链的任意环节捕获异常,且不影响后续任务(或中断流程):
exceptionally:捕获上游任务的异常,返回默认值;handle:同时处理正常结果和异常(类似 try-catch);whenComplete:处理结果或异常(无返回值,仅做通知)。示例:
任务A执行失败后,用 exceptionally 返回默认值,确保任务B仍能正常执行:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 任务A:模拟执行失败
int i = 1 / 0;
return 100;
}).exceptionally(ex -> {
// 捕获任务A的异常,返回默认值
System.out.println("任务A执行失败:" + ex.getMessage());
return 0; // 默认值
}).thenApply(result -> {
// 任务B:使用任务A的结果(正常结果或默认值)
return result * 2;
});
System.out.println("最终结果:" + future.join()); // 输出 0
CompletableFuture 可结合自定义线程池,灵活控制并发度,避免 FutureTask 中可能出现的主线程阻塞问题,尤其适合 I/O 密集型任务(比如:多接口并行调用、文件批量处理)。
特性 | FutureTask | CompletableFuture |
|---|---|---|
引入版本 | JDK 1.5 | JDK 1.8 |
核心功能 | 单个任务异步执行 + 结果获取 | 多任务编排、异步回调、结果组合 |
任务依赖支持 | 不支持(需手动嵌套) | 支持链式调用(thenApply/thenAccept等) |
多任务组合 | 不支持(需手动管理多个 Future) | 支持 allOf/anyOf 组合 |
回调机制 | 无(需主动阻塞/轮询) | 支持(thenAccept/whenComplete等) |
异常处理 | 需手动 try-catch (get() 方法) | 支持链式异常处理(exceptionally/handle) |
线程池依赖 | 需手动创建 ExecutorService | 内置 ForkJoinPool,也可自定义线程池 |
适用场景 | 简单异步任务、需取消任务、低版本JDK | 复杂异步流程、多任务依赖、高并发 |
优先选择 CompletableFuture(JDK 1.8+):
大部分业务场景(尤其是微服务、分布式系统)中,多任务依赖、异步回调是常见需求,CompletableFuture 能显著简化代码复杂度,提升系统吞吐量。
仅在简单场景使用 FutureTask:
若仅需执行单个独立任务,且无需回调、无需组合其他任务,FutureTask 足够简洁(比如:后台计算一个单一值,主线程后续阻塞获取)。
避免使用默认线程池(CompletableFuture):
CompletableFuture 的 supplyAsync/runAsync 默认使用 ForkJoinPool.commonPool(),该线程池是全局共享的,若任务耗时过长或并发过高,可能影响其他任务。建议始终使用自定义线程池:
// 推荐:使用自定义线程池
ExecutorService myPool = Executors.newFixedThreadPool(5);
CompletableFuture.supplyAsync(() -> {
// 任务逻辑
}, myPool);
注意任务取消与中断:
FutureTask 的 cancel(true) 需任务内部响应中断(比如检查 Thread.interrupted());CompletableFuture 的 cancel(true) 同样依赖任务中断支持,且链式任务中,上游任务取消会导致下游任务也被取消。避免过度使用链式调用:
虽然 CompletableFuture 支持长链式调用,但过长的链会降低代码可读性(比如超过5个环节),建议拆分为多个独立的 CompletableFuture,或用 thenCompose 扁平化嵌套。
在实际开发中,除非项目限制 JDK 版本或任务极其简单,否则优先使用 CompletableFuture,它能更优雅地应对高并发、复杂流程的异步需求。