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对象非常简单,可以通过以下几种方式:

  1. 使用CompletableFuture的静态工厂方法:

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!");
  2. 使用默认构造函数创建一个空的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 allOfanyOf
  • 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引入了orTimeoutcompleteOnTimeout方法:

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 需求描述

假设我们在开发一个在线购物平台,用户下单时需要进行以下操作:

  1. 验证用户信息。

  2. 检查库存。

  3. 处理支付。

  4. 生成订单。

我们希望这些操作尽可能并行执行,以提高系统的响应速度。

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来并行执行用户验证、库存检查和支付处理。所有任务都在自定义的线程池中执行,最后通过生成订单来完成整个流程。如果在任何一个步骤中发生异常,系统会捕获并处理。

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

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

相关文章

Django之文件上传(一)

一、环境搭建 建立项目 django-admin startproject project_demo配置数据库(以MySQL为例) # settings.py DATABASES = {default: {ENGINE: django.db.backends.mysql,NAME: django_file4,USER: root,PASSWORD: 123,HOST: 192.168.31.151,PORT: 3306,} }建立模型 class UploadF…

redis 集群 底层原理以及实操

前言 上篇我们讲解了哨兵集群是怎么回事 也说了对应的leader选举raft算法 也说了对应的slave节点是怎么被leader提拔的 主要是比较优先级 比较同步偏移量 比较runid等等 今天我们再说说,其实哨兵也有很多缺点 虽然在master挂了之后能很快帮我们选举出新的master 但是对于单个ma…

【Spring Cloud】分布式配置

目录 未来的开发场景为什么需要配置中心配置实时生效配置管理流程 开源配置中心基本介绍DisconfSpring Cloud ConfigApolloNacos Spring Cloud Config介绍配置管理工具体系 案例需求编写 Config Server1.创建配置文件2.创建项目3.添加依赖4.添加注解5.修改配置文件application.…

Python OCR 文字识别使用模型:读光-文字识别-行识别模型-中英-通用领域

介绍 什么是OCR&#xff1f; OCR是“Optical Character Recognition”的缩写&#xff0c;中文意为“光学字符识别”。它是一种技术&#xff0c;可以识别和转换打印在纸张或图像上的文字和字符为机器可处理的格式&#xff0c;如计算机文本文件。通过使用OCR技术&#xff0c;可…

在iPhone上恢复误删除的微信聊天记录

想知道是否可以恢复 微信iPhone 上误删除的消息&#xff1f;继续阅读以获取所有相关问题的答案。 过去几年&#xff0c;像微信这样的社交媒体应用为我们的生活增添了不少乐趣。它们让我们可以随时随地与朋友和家人保持联系。 微信是一个简化且热门的通信平台&#xff0c;它允…

数据结构 | 详解二叉树——堆与堆排序

&#x1f95d;堆 堆总是一棵完全二叉树。 大堆&#xff1a;父节点总是大于子节点。 小堆&#xff1a;父节点总是小于子节点。 注意&#xff1a;1.同一个节点下的两个子节点并无要求先后顺序。 2.堆可以是无序的。 &#x1f349;堆的实现 &#x1f334;深度剖析 1.父节点和子…

QT截图程序,可多屏幕截图二,增加调整截图区域功能

上一篇QT截图程序&#xff0c;可多屏幕截图只是实现了最基本的截图功能&#xff0c;虽然能用但是缺点也有&#xff0c;没办法更改选中的区域&#xff0c;这在实际使用时不太方便。这篇增加了这个功能。先看看效果。 实现代码为&#xff1a; 头文件 #ifndef MASKWIDGET_H #de…

Matlab|基于PMU相量测量单元进行电力系统电压幅值和相角状态估计

主要内容 程序采用三种方法对14节点和30节点电力系统状态进行评估&#xff1a; ①PMU同步相量测量单元结合加权最小二乘法&#xff08;WLS&#xff09;分析电力系统的电压幅值和相角状态&#xff1b; ②并采用牛顿-拉夫逊方法进行系统潮流计算&#xff0c;结果作为理论分…

LLAMA3==shenzhi-wang/Llama3-8B-Chinese-Chat。windows安装不使用ollama

创建环境&#xff1a; conda create -n llama3_env python3.10 conda activate llama3_env conda install pytorch torchvision torchaudio cudatoolkit11.7 -c pytorch 安装Hugging Face的Transformers库&#xff1a; pip install transformers sentencepiece 下载模型 ht…

开源一个工厂常用的LIMS系统

Senaite是一款强大且可靠的基于Web的LIMS/LIS系统&#xff0c;采用Python编写&#xff0c;构建在Plone CMS基础架构之上。该系统处于积极开发阶段&#xff0c;在灵活的定制空间中为开发人员提供了丰富的功能。其中&#xff0c;Senaite在处理REST的JSON API上做得出色&#xff0…

python -【二】判断语句

判断语句 一、 布尔类型 True&#xff1a;真(1)False&#xff1a;假(0) 比较运算符 运算符实例1 1 True!1 ! 1 Flase<1 < 1 Flse>1 > 1 Flse<1 < 1 True>1 > 1 True b1 True b2 False print(f"b1值是{b1},类型是{type(b1)}") print(…

【Linux】Socket中的心跳机制(心跳包)

Socket中的心跳机制(心跳包) 1. 什么是心跳机制&#xff1f;(心跳包) 在客户端和服务端长时间没有相互发送数据的情况下&#xff0c;我们需要一种机制来判断连接是否依然存在。直接发送任何数据包可以实现这一点&#xff0c;但为了效率和简洁&#xff0c;通常发送一个空包&am…

npm入门介绍

npm&#xff08;Node Package Manager&#xff09;是 Node.js 的包管理工具&#xff0c;用于安装、管理和共享 JavaScript 代码包。它是全球最大的软件注册表&#xff0c;拥有数百万个开源包&#xff0c;为开发者提供了丰富的资源和工具。以下是 npm 的详细介绍&#xff1a; 1…

vs工程添加自定义宏

一、简介 用户可以添加自定义宏变量方便工程路径名称的修改和配置 例&#xff1a;$(SolutionDir) 为解决方案路径&#xff0c;$(PojectDir) 为工程所在路径 测试环境&#xff1a;vs2017&#xff0c;qt5.14.0 二、配置 1、打开属性窗口&#xff1a;视图-》其他窗口-》属性管…

四数之和-力扣

本题在三数之和的基础上&#xff0c;再增加一重循环进行解答 首先注意的点是&#xff0c;一级剪枝处理&#xff0c;target > 0 && nums[i] > target 此处只有整数才可剪枝处理&#xff0c;如果target为负数&#xff0c;nums[i] < target&#xff0c;也不能代…

精准操控时间的艺术:JavaScript节流函数的深度探索与实践【含代码示例】

精准操控时间的艺术&#xff1a;JavaScript节流函数的深度探索与实践【含代码示例】 节流基础&#xff1a;概念与作用实现策略&#xff1a;案例展示案例一&#xff1a;基础定时器实现案例二&#xff1a;立即执行版本案例三&#xff1a;使用requestAnimationFrame实现动画节流 功…

蓝桥杯-AB路线(详细原创)

问题描述&#xff1a; 有一个由 N M 个方格组成的迷宫&#xff0c;每个方格写有一个字母 A 或者 B。小蓝站在迷宫左上角的方格&#xff0c;目标是走到右下角的方格。他每一步可以移动到上下左右相邻的方格去。 由于特殊的原因&#xff0c;小蓝的路线必须先走 K 个 A 格子、再…

前端面试题日常练-day40 【面试题】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末 1. Bootstrap 的栅格系统是基于&#xff08; &#xff09;进行布局的。A. 像素 B. 百分比 C. 媒体查询 2. 在 Bootstrap 中&#xff0c;要创建一个按钮&#xff0c;可以使用&#xff08; &#xff…

【CSharp】判断目录以及文件是否存在

【CSharp】判断目录以及文件是否存在 1.背景2.判断目录3.判断文件1.背景 我们在进行磁盘IO的时候进行需要判断目录、文件是否存在,根据判断结果再做进一步的操作。 其中判断目录是否存在,涉及Directory.Exists(String) 方法; 命名空间:System.IO 方法功能:确定给定路径是…

Spring OAuth2:开发者的安全盾牌!(下)

上文我们教了大家如何像海盗一样寻找宝藏&#xff0c;一步步解锁令牌的奥秘&#xff0c;今天将把更加核心的技巧带给大家一起学习&#xff0c;共同进步&#xff01; 文章目录 6. 客户端凭证与密码模式6.1 客户端凭证模式应用适用于后端服务间通信 6.2 密码模式考量直接传递用户…