当前位置: 首页 > news >正文

Java 线程池(第十篇):(收官篇)CompletableFuture 异步编排实战 —— 多任务并行、结果汇总、超时控制与线程池协作

completableFuture 异步编排实战 —— 多任务并行、结果汇总、超时控制与线程池协作

如果说前 1–9 篇解决的是“线程池如何安全、稳定地跑”
那么这一篇解决的是:

如何把多个异步任务“编排”成一个可读、可控、可维护的并发流程。

这正是现代 Java 并发从ThreadPoolExecutor → CompletableFuture的进化方向。

一、为什么需要 CompletableFuture?

先看一个你一定写过的代码:

Future<User> f1 = pool.submit(() -> this.loadUser()); Future<User> f2 = pool.submit(() -> this.loadUser()); User user = f1.get(); Order order = f2.get();

问题很明显:

  • get() 阻塞
  • 顺序代码读起来像同步
  • 异常处理零散
  • 任务依赖一多,代码迅速失控

CompletableFuture 的核心价值只有一句话:

用“声明式”的方式,描述异步任务之间的关系,而不是用 get() 等结果。

二、CompletableFuture 和线程池的关系(先搞清楚)

1️⃣ CompletableFuture ≠ 线程池

  • CompletableFuture 是异步任务编排工具

  • 线程池是执行引擎

2️⃣ 默认线程池是 ForkJoinPool(不推荐直接用)

CompletableFuture.supplyAsync(() -> work());

默认使用:

ForkJoinPool.commonPool()

👉生产环境强烈建议:显式传入你自己的线程池(第五篇)

CompletableFuture.supplyAsync(() -> work(), ioPool);

三、最核心的三种编排模式(80% 场景)

1️⃣ thenApply —— 单任务链式变换

CompletableFuture .supplyAsync(() -> 1, pool) .thenApply(x -> x + 1) .thenApply(x -> x * 2) .thenAccept(System.out::println);
  • 同一条任务链
  • 上一步完成 → 执行下一步
  • 适合数据转换

2️⃣ thenCompose —— 依赖型异步(避免嵌套)

CompletableFuture<User> f = loadUserAsync(id) .thenCompose(user -> loadProfileAsync(user));

等价于(但比它优雅得多):

CompletableFuture<User> f = loadUserAsync(id) .thenApply(user -> loadProfileAsync(user)) .get(); // ❌

一句话:

thenCompose = “异步版的 flatMap”

3️⃣ thenCombine —— 并行任务结果合并(非常常用)

CompletableFuture<User> userFuture = loadUserAsync(id); CompletableFuture<Order> orderFuture = loadOrderAsync(id); CompletableFuture<UserInfo> result = userFuture.thenCombine(orderFuture, (user, order) -> new UserInfo(user, order));

✔ 并行执行
✔ 都完成后才合并
✔ 没有 get()

四、allOf / anyOf:真正的“并行编排”

allOf:全部完成

CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2, f3); all.thenRun(() -> System.out.println("all done"));

⚠ 注意:allOf不帮你收集结果,你需要自己 get(或 join)

List<Result> results = List.of(f1, f2, f3) .stream() .map(CompletableFuture::join) .toList();

anyOf:任意一个完成

CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2, f3); all.thenRun(() -> System.out.println("all done"));

⚠ 注意:allOf不帮你收集结果,你需要自己 get(或 join)

List<Result> results = List.of(f1, f2, f3) .stream() .map(CompletableFuture::join) .toList();

anyOf:任意一个完成

CompletableFuture<Object> any = CompletableFuture.anyOf(f1, f2); any.thenAccept(r -> System.out.println("first = " + r));

常用于:

  • 多数据源兜底
  • 多节点竞速

五、异常处理:这是 CompletableFuture 的强项

1️⃣ exceptionally —— 兜底恢复

CompletableFuture .supplyAsync(() -> risky(), pool) .exceptionally(e -> { log.error("error", e); return defaultValue; });

2️⃣ handle —— 成功 / 失败都处理

future.handle((r, e) -> { if (e != null) { return fallback; } return r; });

一句工程经验:

CompletableFuture 的异常是“流的一部分”,不是打断流程。

六、超时控制(非常关键)

Java 9+ 推荐方式

future .orTimeout(2, TimeUnit.SECONDS) .exceptionally(e -> fallback);

或者:

future .completeOnTimeout(fallback, 2, TimeUnit.SECONDS);

Future.get(timeout)的优势:

  • 不阻塞线程
  • 超时是异步语义的一部分

七、CompletableFuture + 线程池的最佳实践

✔ 1)明确线程池职责

  • IO 任务 → ioPool

  • CPU 任务 → cpuPool

  • 定时 → scheduledPool

CompletableFuture.supplyAsync(this::loadData, ioPool)

✔ 2)不要在 CompletableFuture 里 get()

// ❌ 反模式 future.thenApply(r -> anotherFuture.get());

✔ 3)异常必须收敛在链路末端

future .thenApply(...) .thenApply(...) .exceptionally(this::fallback);

✔ 4)避免在 commonPool 跑重任务

ForkJoinPool 是共享资源,容易拖垮 JVM。

八、一个完整实战 Demo

补充知识点:

Java 的“高阶函数”到底是什么:Runnable / Callable 就是函数参数

CompletableFuture<User> userFuture = CompletableFuture.supplyAsync(this::loadUser, ioPool); CompletableFuture<Order> orderFuture = CompletableFuture.supplyAsync(this::loadOrder, ioPool); CompletableFuture<UserInfo> result = userFuture .thenCombine(orderFuture, UserInfo::new) .orTimeout(2, TimeUnit.SECONDS) .exceptionally(e -> { log.error("timeout or error", e); return UserInfo.empty(); }); result.thenAccept(info -> render(info));

这个 Demo 覆盖了:

  • 并行
  • 合并
  • 超时
  • 异常
  • 自定义线程池

九、和前 9 篇的“闭环关系”

你现在拥有的是一套完整体系:

  • 线程池(1–5)
  • 任务提交与异常(6–7)
  • 可观测性(8)
  • 背压(9)
  • 异步编排(10) ← 收官

一句总结:

ThreadPoolExecutor 决定“系统能不能跑”,
CompletableFuture 决定“并发代码能不能写得优雅、可维护”。

十、全专栏终极总结

  • 线程池是并发执行的基础设施

  • 背压决定系统是否稳定

  • 监控决定问题是否可见

  • CompletableFuture 决定异步逻辑是否可维护

  • 并发不是“多开线程”,而是“正确组织任务关系”

到这里,已经是一个完整、工程级、的体系。

http://www.cnnetsun.cn/news/107551.html

相关文章:

  • hasattr()函数和getattr()函数
  • Windows系统清理优化神器!支持Win10/11磁盘空间注册表清理,开机自启动项管理、程序应用安装更新卸载,电脑性能优化设置增强!
  • EmotiVoice语音合成日志记录规范:便于调试与审计
  • EmotiVoice语音合成多区域部署架构设计
  • 不常用但超实用!QSpinBox 九大隐藏技巧
  • ChatGPT 说:豆包手机被微信“拒绝”,背后隐藏的是技术与生态的深层冲突
  • C++基础知识点——5个重要位运算技巧(通俗易懂版)
  • ScriptHookV模组开发实战:从入门到精通的完整指南
  • 重磅!AI应用架构师力推的企业虚拟运营方案_副本
  • pose-search:人体动作分析与姿态搜索终极指南
  • 终极隐私保护方案:用Buzz实现完全离线的语音转文字
  • DTLN实时降噪技术:用AI算法打造纯净语音体验的完整指南
  • 移动端视频录制技术革新:基于MediaRecorder的高性能解决方案
  • EmotiVoice与RVC的区别是什么?一文讲清两者定位差异
  • EmotiVoice语音合成中断怎么办?常见错误排查
  • ComfyUI-SeedVR2视频超分插件完整安装与配置指南
  • 开源TTS新星崛起:EmotiVoice为何备受开发者青睐?
  • 记录Kibana多实例竞争导致的迁移锁
  • PySlowFast混合精度训练终极技巧:快速突破视频模型性能瓶颈的完整解决方案
  • 多肽合成丨HNGS14G CAS号: 330936-70-4
  • 43、Linux 网络安全:防火墙与认证机制深度解析(上)
  • 44、一次性密码与安全外壳:保障系统安全登录的有效手段
  • PostgreSQL pgvector扩展:向量相似性搜索的终极实践指南
  • 50、Linux系统安装与磁盘分区全攻略
  • 27、Linux 路由软件配置指南
  • KISS FFT轻量级信号处理终极指南:从入门到精通
  • 快速掌握X-AnyLabeling:GeCO模型在目标计数中的完整实践指南
  • Mac M1芯片运行EmotiVoice性能表现如何?
  • 如何快速构建Next.js多租户认证系统:终极完整指南
  • 计算机Java毕设实战-基于JAVA的北京市公交管理系统基于Java的城市公交查询管理系统的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】