CompletableFuture 的前世今生

CompletableFuture 的前世今生

一、背景:Java 异步编程的演进

CompletableFuture 之前,Java 的异步编程主要通过线程、Future 等实现。

flowchart LRA[Before Java 5] -->|单线程| B[Main Thread]B --> C[手动创建线程]D[Java 5 Future] -->|线程池| E[异步任务]E --> F[阻塞获取结果]G[Java 8 CompletableFuture] -->|链式调用| H[非阻塞流水线]H --> I[结果转换]I --> J[异常处理]J --> K[组合多个任务]

1. Future 接口(Java 5+)

  • 作用:通过 ExecutorService.submit() 提交任务,返回 Future 对象,用于获取异步任务的结果。
  • 局限性
    • 无法手动设置结果或异常。
    • 无法组合多个异步操作(如任务A完成后触发任务B)。
    • 只能通过阻塞的 get() 方法等待结果,缺乏非阻塞回调机制。
ExecutorService executor = Executors.newFixedThreadPool(2);// 1. 基本 Future 示例
Future<Integer> future = executor.submit(() -> {Thread.sleep(1000);return 42;
});// 阻塞获取结果(无法实现非阻塞回调)
Integer result = future.get(); // 2. 组合多个 Future 的困境
Future<String> f1 = executor.submit(task1);
Future<String> f2 = executor.submit(task2);// 需要手动协调多个 Future(复杂且容易出错)
String combined = f1.get() + f2.get(); 

2. 回调地狱(Callback Hell)

  • 开发者需要通过嵌套回调处理多个异步任务,代码可读性和维护性差。
  • 例如:数据库查询完成后触发网络请求,再触发文件写入操作。
// 传统 Future 实现(回调地狱)
Future<Order> orderFuture = queryOrder();
orderFuture.get(); // 阻塞
Future<Payment> paymentFuture = processPayment(orderFuture.get());
paymentFuture.get(); // 再次阻塞
Future<Notification> notifyFuture = sendNotification(paymentFuture.get());

3. 第三方库的尝试

  • 如 Guava 的 ListenableFuture,支持添加回调,但需要额外依赖。

二、CompletableFuture 的诞生(Java 8+)

Java 8 引入了 CompletableFuture,目标是提供更灵活的异步编程模型,支持非阻塞操作链式组合

架构继承:兼容性设计

classDiagramclass Future {<<interface>>+get()+isDone()+cancel()}class CompletionStage {<<interface>>+thenApply()+thenCompose()+thenCombine()}class CompletableFuture {+supplyAsync()+thenApplyAsync()+complete()}Future <|.. CompletableFutureCompletionStage <|.. CompletableFuture
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {// 维护异步计算结果volatile Object result;       // 具体结果或 AltResult// 实现 Future 接口的阻塞获取public T get() throws InterruptedException, ExecutionException {Object r;if ((r = result) == null)r = waitingGet(true);return (T) reportJoin(r);}// 实现 CompletionStage 的链式调用public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) {return uniApplyStage(screenExecutor(executor), fn);}
}

关键设计考量

  1. 向后兼容:使现有基于 Future 的代码无需修改即可使用 CompletableFuture
  2. 接口契约:保持异步计算结果的获取/取消等基础能力
  3. 类型系统:通过接口继承实现多态特性

核心设计思想

  • 基于 Future 接口CompletionStage 接口
    • Future:保留基础的异步结果获取能力。
    • CompletionStage:定义异步操作的链式组合(如 thenApply, thenCombine 等)。
  • 借鉴了函数式编程和 Promise 模式(类似 JavaScript 的 Promise)。

核心升级点

  1. 被动拉取主动推送 的结果处理
  2. 单任务流水线 的异步操作
  3. 新增 异常传播机制exceptionally()/handle()

示例代码

// 1. 异步任务创建
CompletableFuture.supplyAsync(() -> "Hello").thenApply(s -> s + " World")  // 转换结果.thenAccept(System.out::println); // 消费结果// 2. 组合多个 Future
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> 20);cf1.thenCombine(cf2, (a, b) -> a + b).thenAccept(sum -> System.out.println("Sum: " + sum));// 3. 异常处理
CompletableFuture.supplyAsync(() -> {if (new Random().nextBoolean()) throw new RuntimeException("Oops");return "Success";}).exceptionally(ex -> "Fallback: " + ex.getMessage()).thenAccept(System.out::println);

三、核心特性

CompletableFuture 的核心优势在于其灵活的组合能力与异步流程控制:

mindmaproot((CompletableFuture))创建方法supplyAsyncrunAsynccompletedFuture转换方法thenApplythenCompose消费方法thenAcceptthenRun组合方法thenCombineallOfanyOf异常处理exceptionallyhandle

1. 手动完成任务

  • 可以显式设置结果或异常:
    CompletableFuture<String> future = new CompletableFuture<>();
    future.complete("Result");    // 手动设置结果
    future.completeExceptionally(new RuntimeException());  // 手动设置异常
    

2. 链式组合操作

  • 转换结果thenApply()
    future.thenApply(result -> result + " processed");
    
  • 消费结果thenAccept(), thenRun()
    future.thenAccept(System.out::println);
    
  • 组合多个 Future
    • 顺序组合thenCompose()
      future.thenCompose(result -> anotherFuture);
      
    • 并行组合thenCombine()
      future1.thenCombine(future2, (a, b) -> a + b);
      
  • 等待多个任务allOf(), anyOf()
    CompletableFuture.allOf(future1, future2).join();
    

3. 异常处理

  • 通过 exceptionally()handle() 捕获异常:
    future.exceptionally(ex -> "Fallback value");
    

4. 异步执行器(Executor)

  • 默认使用 ForkJoinPool.commonPool(),也支持自定义线程池:
    future.supplyAsync(() -> "Task", customExecutor);
    

四、典型应用场景

  1. 并行执行多个独立任务
    CompletableFuture<User> userFuture = fetchUserAsync();
    CompletableFuture<Order> orderFuture = fetchOrderAsync();
    userFuture.thenCombine(orderFuture, (user, order) -> buildResponse(user, order));
    
  2. 服务调用链(微服务场景)
    CompletableFuture<Response> future = login().thenCompose(token -> fetchData(token)).thenApply(data -> process(data)).exceptionally(ex -> handleError(ex));
    
  3. 超时控制与降级
    future.completeOnTimeout("default", 1, TimeUnit.SECONDS);
    

五、最佳实践建议

  1. 线程池选择:默认使用 ForkJoinPool.commonPool(),密集任务建议使用自定义线程池
  2. 异常处理:始终使用 exceptionally() 或 handle() 处理异常
  3. 超时控制:Java 9+ 使用 orTimeout() 方法
  4. 资源释放:使用 whenComplete() 进行资源清理
  5. 组合优先:使用 thenCompose() 代替嵌套的 thenApply()

CompletableFuture 的演进体现了 Java 并发编程从命令式到声明式的转变,通过函数式编程实现了更优雅的异步处理流水线。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/906930.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文速通Python并行计算:04 Python多线程编程-多线程同步(上)—基于条件变量、事件和屏障

本文介绍了Python多线程同步的三种机制:条件变量(Condition)、事件(Event)和屏障(Barrier),条件变量指的是线程等待特定条件满足后执行,适用于生产者-消费者模型;Event指的是线程通过事件标志进行同步,适用于线程间简单通信;Barrier指的是多个线程需同步到同一阶段…

docker desktop windows安装

我的机器windows 11 家庭版 下载docker desktop for windows 就直接安装了。安装后打开,遇到了界面转圈圈加载不出来问题,docker engine也是stopped. 病急乱投医,先是说要启用hyper-v,控制面板=》程序和功能里没有发现有hyper-v,一看是家庭版,网上倒是有一个脚本可以在家…

C语言打卡学习第6天(2025.3.25)(补发)

只做了一些有关循环分支函数求值的题,感觉循环函数其实差不多,只有一些细微差别,可能是做的题还不够多或者看运用场景吧

C语言打卡学习第5天(2025.3.24)(补发)

1、把char,getchar,putchar简单看了一下,求ascii值之类的 之类的简单看了一下 2、交换值那一题很奇怪,结果我输出的跟答案要求是一样的,交过去之后显示答案错误,白天的时候问一下

Vulnstack红日靶场通关(持续更新)

带你速通内网渗透相关知识点!!!Vulnstack通关 来源于《内网渗透实战攻略》实战部分 个人是写下自己的笔记 攻击链:探索发现阶段->入侵和感染阶段->攻击和利用阶段->探索感知阶段->传播阶段->持久化和恢复阶段 Windows权限级别前置知识:权限层级 账户类型 权…

Ubuntu 24.04安装MySQL,并且配置外网访问

安装启动更新软件包列表sudo apt update安装MySQL软件包sudo apt install mysql-server启动MySQL服务sudo systemctl start mysql重启命令:systemctl restart mysql配置外网访问 需要修改一个配置 vim /etc/mysql/mysql.conf.d/mysqld.cnf注释掉 这行 配置 bind-address …

2022CCPC Online Contest G - Name the Puppy

对正串和反串分别建立 Trie 树,定义 \(dp[i][j]\) 表示正串 Trie 树上编号为 \(i\) 的点匹配反串 Trie 树上编号为 \(j\) 的点所能拼出最长 anti-border 的长度。 如此,从根节点开始搜索,直到无法匹配为止都可以搜,搜到底后回到根节点继续匹配,可以证明,拼出来的 anti-bo…

互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp智能体框架开发语音交互

前言 前段时间太忙了博客一直都没来得及更新,但是不代表我已经停止开发了,刚好最近把语音部分给调整了一下,所以就来分享一下具体的内容了。我想说一下,更新晚还是有好处的,社区已经有很多的小伙伴自己实现了一些语音对话功能的案例,比如小智也有.NET客户端了,还有就是一…

【AI News | 20250327】每日AI进展

AI Repos 1、playwright-mcp 使用Playwright提供浏览器自动化功能的MCP服务,核心是让LLM通过结构化的可访问性快照与网页交互,不需要依赖截图或视觉模型。可以用来自动填写网页表单、自动收集网页信息、自动进行网页测试等。支持两种模式:快照模式(默认):使用可访问性快照…

markdown常用命令行格式

Markdown 主要命令(语法)如下:标题 使用 # 号表示标题,# 的个数决定标题的级别:一级标题 二级标题 三级标题 四级标题 五级标题 六级标题段落 & 换行 直接输入文字形成段落,使用两个以上空格或 进行换行:这是一个段落。 这是同一段的下一行。 使用 <br> 也可…

微调可以获得什么

1.改变模型的行为: 使模型的响应更稳定; 使模型聚焦于某一领域; 发展期潜力,在某一方面更加出色,比如对话 2.获取新的知识: 学习预训练阶段没学过的知识; 纠正过时的错误和信息;

2022CCPC Online Contest G - Count Permutation

利用大写字母较少的性质,记录两个大写字母中间的串是否相等来进行转移。 设 \(f[i][j]\) 表示考虑用到第 \(i\) 个大写字母的时候,\(s\) 匹配到第 \(j\) 个字符时最长匹配数。当前大写字母 \(t[pos[i]] = s[j]\) 时,显然有 \(f[i][j] = f[i][j - 1] + 1\)如果 \(s[pos[i - 1…