CompletableFuture详细讲解
目录
一、基本概念
1.1 异步编程
1.2 CompletableFuture简介
二、创建和完成CompletableFuture
2.1 创建CompletableFuture对象
2.2 手动完成CompletableFuture
2.3 异常完成CompletableFuture
三、异步计算和回调
3.1 异步任务的执行
3.2 处理计算结果
四、组合多个CompletableFuture
4.1 thenCombine
4.2 thenCompose
4.3 allOf和anyOf
五、异常处理
5.1 handle
5.2 exceptionally
六、高级特性
6.1 自定义执行器
6.2 超时控制
七、实战案例
7.1 需求描述
7.2 代码实现
Java的CompletableFuture是Java 8中引入的一个功能强大的类,用于处理异步编程。它不仅提供了一种方式来表示异步计算,还提供了丰富的API来进行复杂的异步编排和处理。本文将详细讲解CompletableFuture的基本概念、使用方法以及一些高级特性,并结合实例代码进行说明。
一、基本概念
1.1 异步编程
异步编程是一种并发编程的形式,通过非阻塞方式执行任务。传统的同步编程中,任务必须按顺序执行,每个任务必须等待前一个任务完成。然而,在异步编程中,任务可以在后台执行,主线程无需等待任务完成,因而可以继续处理其他任务。这种方式在提高程序响应速度和资源利用率方面有很大优势。
1.2 CompletableFuture简介
CompletableFuture是Java提供的一个实现Future接口的类,它不仅支持传统的Future接口方法,还引入了许多新的方法来支持回调、组合、处理异常等功能。通过这些方法,开发者可以更方便地编写异步代码。
二、创建和完成CompletableFuture
2.1 创建CompletableFuture对象
创建一个CompletableFuture对象非常简单,可以通过以下几种方式:
-
使用
CompletableFuture的静态工厂方法:CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!");
-
使用默认构造函数创建一个空的
CompletableFuture,然后在未来的某个时间点手动完成它:CompletableFuture<String> future = new CompletableFuture<>(); // 在其他线程或任务中完成这个future future.complete("Hello, World!");
2.2 手动完成CompletableFuture
你可以通过complete方法手动完成一个CompletableFuture:
CompletableFuture<String> future = new CompletableFuture<>();
future.complete("Hello, World!");
如果已经完成的CompletableFuture再次调用complete,将不会改变其状态。
2.3 异常完成CompletableFuture
CompletableFuture也可以以异常方式完成:
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException("Something went wrong"));
三、异步计算和回调
3.1 异步任务的执行
CompletableFuture提供了多种方法来启动异步任务,例如:
-
runAsync:执行不返回结果的异步任务。 -
supplyAsync:执行并返回结果的异步任务。
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {// 异步执行的任务System.out.println("Hello from a different thread!");
});
CompletableFuture<String> futureWithResult = CompletableFuture.supplyAsync(() -> {// 异步执行的任务,返回结果return "Result of the async computation";
});
3.2 处理计算结果
CompletableFuture提供了多种方法来处理异步任务的结果,例如:
-
thenApply:当CompletableFuture完成时,对其结果进行处理,并返回一个新的CompletableFuture。 -
thenAccept:当CompletableFuture完成时,消费其结果,但不返回新的CompletableFuture。 -
thenRun:当CompletableFuture完成时,运行一个任务,不关心其结果。
CompletableFuture.supplyAsync(() -> "Hello").thenApply(result -> result + ", World!").thenAccept(System.out::println);
上述代码中,supplyAsync方法执行异步任务并返回结果"Hello"。thenApply方法对结果进行处理,得到"Hello, World!"。thenAccept方法消费处理后的结果,并打印输出。
四、组合多个CompletableFuture
CompletableFuture提供了多种方式来组合多个异步任务:
4.1 thenCombine
thenCombine用于将两个CompletableFuture的结果进行组合,并返回一个新的CompletableFuture:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);
combinedFuture.thenAccept(System.out::println); // 输出 "Hello World"
4.2 thenCompose
thenCompose用于将一个CompletableFuture的结果作为另一个CompletableFuture的输入,类似于flatMap:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello").thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
future.thenAccept(System.out::println); // 输出 "Hello World"
4.3 allOf和anyOf
-
allOf:等待所有提供的CompletableFuture都完成。 -
anyOf:只要任意一个CompletableFuture完成即可。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result from future1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result from future2");
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
allOfFuture.thenRun(() -> System.out.println("All futures completed"));
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2);
anyOfFuture.thenAccept(result -> System.out.println("First completed future result: " + result));
五、异常处理
在处理异步任务时,异常处理是不可避免的。CompletableFuture提供了多种方式来处理异常:
5.1 handle
handle方法用于处理正常结果和异常情况:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (Math.random() > 0.5) {throw new RuntimeException("Something went wrong");}return "Success";
});
future.handle((result, ex) -> {if (ex != null) {return "Exception: " + ex.getMessage();}return result;
}).thenAccept(System.out::println);
5.2 exceptionally
exceptionally方法仅处理异常情况:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (Math.random() > 0.5) {throw new RuntimeException("Something went wrong");}return "Success";
});
future.exceptionally(ex -> "Exception: " + ex.getMessage()).thenAccept(System.out::println);
六、高级特性
6.1 自定义执行器
默认情况下,CompletableFuture使用ForkJoinPool.commonPool()作为其默认的线程池。你可以自定义执行器来控制任务的执行方式:
Executor executor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello", executor).thenApplyAsync(result -> result + " World", executor);
future.thenAcceptAsync(System.out::println, executor);
6.2 超时控制
在某些场景下,处理超时是必要的。Java 9引入了orTimeout和completeOnTimeout方法:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {throw new IllegalStateException(e);}return "Result";
});
future.orTimeout(1, TimeUnit.SECONDS).exceptionally(ex -> "Timeout occurred: " + ex.getMessage()).thenAccept(System.out::println);
七、实战案例
为了更好地理解CompletableFuture,我们来看一个实际的例子:模拟一个复杂的业务场景,包含多个异步任务的组合和处理。
7.1 需求描述
假设我们在开发一个在线购物平台,用户下单时需要进行以下操作:
-
验证用户信息。
-
检查库存。
-
处理支付。
-
生成订单。
我们希望这些操作尽可能并行执行,以提高系统的响应速度。
7.2 代码实现
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class OnlineShopping {
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {CompletableFuture<Void> orderFuture = CompletableFuture.supplyAsync(() -> verifyUser("user123"), executor).thenCombineAsync(CompletableFuture.supplyAsync(() -> checkInventory("item456"), executor), (userVerified, inventoryChecked) -> {if (userVerified && inventoryChecked) {return processPayment("user123", "
item456");} else {throw new RuntimeException("User verification or inventory check failed");}}, executor).thenApplyAsync(paymentProcessed -> generateOrder("user123", "item456"), executor).thenAcceptAsync(order -> System.out.println("Order completed: " + order), executor).exceptionally(ex -> {System.err.println("Order processing failed: " + ex.getMessage());return null;});
orderFuture.join(); // 等待所有操作完成}
private static boolean verifyUser(String userId) {// 模拟用户验证System.out.println("Verifying user: " + userId);return true;}
private static boolean checkInventory(String itemId) {// 模拟库存检查System.out.println("Checking inventory for item: " + itemId);return true;}
private static boolean processPayment(String userId, String itemId) {// 模拟支付处理System.out.println("Processing payment for user: " + userId + " and item: " + itemId);return true;}
private static String generateOrder(String userId, String itemId) {// 模拟订单生成System.out.println("Generating order for user: " + userId + " and item: " + itemId);return "Order123";}
}
在这个示例中,我们使用了多个CompletableFuture来并行执行用户验证、库存检查和支付处理。所有任务都在自定义的线程池中执行,最后通过生成订单来完成整个流程。如果在任何一个步骤中发生异常,系统会捕获并处理。
相关文章:
CompletableFuture详细讲解
目录 一、基本概念 1.1 异步编程 1.2 CompletableFuture简介 二、创建和完成CompletableFuture 2.1 创建CompletableFuture对象 2.2 手动完成CompletableFuture 2.3 异常完成CompletableFuture 三、异步计算和回调 3.1 异步任务的执行 3.2 处理计算结果 四、组合多个…...
【Linux】初识Linux和Linux环境配置
1.什么是Linux操作系统 说到电脑系统 我想有大多数人会脱口而出:windows、mac 是的,这也是如今市场上主流的两种操作系统。 但是对于IT相关的人士来说,还有一种系统也是必须有姓名 那就是Linux Linux,Linux Is Not UniX 的…...
redis-cli help使用
1. redis-cli命令使用—先连接上服务器 连接到 Redis 服务器: 使用 redis-cli 命令即可连接到本地运行的 Redis 服务器,默认连接到本地的 6379 端口。 redis-cli如果 Redis 服务器不在本地或者端口不同,可以使用 -h 和 -p 参数指定主机和端…...
中华活页文选高中版投稿发表
《中华活页文选(高中版)》创刊于1960年,是中宣部所属中国出版传媒股份有限公司主管、中华书局主办的国家级基础教育期刊,曾获得“中国期刊方阵双效期刊”、国家新闻出版广电总局推荐的“百种优秀报刊”等荣誉称号。本刊以高中学科…...
[图解]企业应用架构模式2024新译本讲解02-表数据入口
1 00:00:00,420 --> 00:00:04,330 这个案例,我们就是用书上的案例了 2 00:00:06,080 --> 00:00:08,860 收入确认的一个案例 3 00:00:09,510 --> 00:00:11,100 书上讲了,收入确认 4 00:00:13,330 --> 00:00:15,270 就是说,你给…...
SSE(Server Sent Event) 踩坑留念
整条链路是 客户端A --> 服务端 A —> 服务端 B 我负责服务端 A 此时要注意 Client 中的 processes 的写法 Post(value “/v2/xx”, processes MediaType.TEXT_EVENT_STREAM) 这样写是一直报错的 改成下面的写法才可以 Post(value “/v2/xx”, processes MediaT…...
plt.xticks()的作用
参考: https://blog.csdn.net/weixin_41796265/article/details/131442400 plt.xticks() 是 Matplotlib 库中的一个函数,用于设置坐标轴刻度的位置和标签。 它的作用包括: 设置 x 轴刻度的位置:可以通过传递一个数组或列表来设…...
开发者的福音:免去搭建服务,让你的应用开发变得像吃蛋糕一样简单!
传统应用开发的"噩梦" 想象一下,你正在准备一场盛大的晚宴,但必须从零开始建造厨房、种植食材、甚至学习烹饪技巧。这就是传统应用开发的现状——你不仅要设计数据库、编写API接口,还要处理对象存储、实时数据库、云数据库等一系列…...
AVL树的模拟实现
我们上期提到了二叉搜索树,只是简单的讲了一下原理,那么今天我们就讲一下AVL树。 目录 AVL树的概念AVL树的实现AVL树的架构insert插入引用pair对象引进parent指针仅插入数据调节平衡因子情况1:插入在父亲的右边,父亲的平衡因子后…...
php 一个数组中的元素是否在一个字符串中包含
php 一个数组中的元素是否在一个字符串中包含 要检查一个数组中的元素是否在一个字符串中出现,你可以使用strpos()函数。这个函数返回子字符串首次出现的位置索引,如果没有找到,它会返回false。 $array [apple, banana, cherry]; $string …...
conda修改环境名称后,无法安装包,显示no such file
1问题描述 原本创建环境时设置的名字不太合适,但是因为重新创建环境很麻烦,安装很多包。。所以想直接对包名进行修改,本人采用的方式是直接找到conda环境的文件目录,然后修改文件名,简单粗暴。确实修改成功了…...
linux安装mysql【linux】
linux安装mysql【linux】 前言版权推荐CentOS7.9安装mysql8.0【linux】yum安装rpm安装 最后 前言 2024-5-13 15:52:22 以下内容源自《【linux】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客主页是https://jss…...
C 语言实例 - 表格形式输出数据
将 1~100 的数据以 10x10 矩阵格式输出。 #include <stdio.h>int main() {int i, j, count;for(i 1; i < 10; i) {for(j i; j <100; j 10 )printf(" %3d", j);printf("\n");}return 0; }运行结果: 1 11 21 31 41 51 61 …...
markdown语法保存
这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…...
数据结构(八)二叉树、哈希查找
文章目录 一、树(一)概念1. 前序遍历:根左右2. 中序遍历:左根右3. 后序遍历:左右根4. 层序遍历:需要借助队列实现 (二)代码实现:二叉树1. 结构体定义2. 创建二叉树1. 注意…...
uniApp 创建Android.keystore证书IOS的证书
Android 证书 1、安装JRE环境 可从Oracle官方下载jre安装包:https://www.oracle.com/technetwork/java/javase/downloads/index.html 打开命令行(cmd),输入以下命令: //切换工作目录到f:路径 D: //将jre命令添加到…...
怎么藏族翻译中文在线翻译?更好地了解藏族文化
怎么藏族翻译中文在线翻译?着全球化的发展,语言交流的重要性日益凸显。藏族,作为中国的一个古老而神秘的民族,其语言对于很多人来说充满了神秘感。然而,在今天的数字化时代,我们有了更多的工具来打破语言壁…...
模拟集成电路(5)----单级放大器(共栅级)
模拟集成电路(5)----单级放大器(共栅级) 有一些场合需要一些小的输入电阻(电流放大器) 大信号分析 − W h e n V i n ≥ V B − V T H ∙ M 1 i s o f f , V o u t V D D − F o r L o w e r V i n I d 1 2 μ n C o x W L ( V…...
学习笔记——数据通信基础——数据通信网络(网络工程师)
网络工程师 网络工程,就是围绕着网络进行的一系列的活动,包括∶网络规划、设计、实施、调试、排错等。网络工程设计的知识领域很宽广,其中路由和交换是计算机网络的基本。 网络工程师∶是在网络工程领域,掌握专业的网络技术&…...
将本地项目上传到 gitee 仓库
1、创建 gitee 仓库 到 gitee 官网,新建仓库 配置新建仓库 完成仓库的创建 项目上传到仓库 上传项目需要安装git git官方下载地址:git下载地址 安装完成,前往本地项目所在文件夹,右击选择 Git Bash Here 刚下载完成需要配置G…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...
python可视化:俄乌战争时间线关键节点与深层原因
俄乌战争时间线可视化分析:关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一,自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具,系统分析这场战争的时间线、关键节点及其背后的深层原因,全面…...
