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

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

相关文章:

  • 【MySQL精通之路】全文搜索(5)-限制
  • Java break细节(标签)
  • Linux: network: tcp spurious retrans 的一个原因
  • C 语言实例 - 表格形式输出数据
  • Python打包篇-exe
  • MFC工控项目实例之一主菜单制作
  • 【MATLAB源码-第217期】基于matlab的16QAM系统相位偏移估计HOS算法仿真,对比补偿前后的星座图误码率。
  • Kubernetes 容器编排
  • CS西电高悦计网课设——校园网设计
  • 基于心电疾病分类的深度学习模型部署应用于OrangePi Kunpeng Pro开发板
  • Leetcode:找出峰值
  • 永久代(Permanent Generation)和元空间(Metaspace)
  • MySQL的安全性
  • 前端 CSS 经典:filter 滤镜
  • 学生管理系统 面向对象
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 4个实用的微服务测试策略
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • IOS评论框不贴底(ios12新bug)
  • JavaScript-Array类型
  • Laravel5.4 Queues队列学习
  • MYSQL 的 IF 函数
  • PHP 7 修改了什么呢 -- 2
  • Python - 闭包Closure
  • Python爬虫--- 1.3 BS4库的解析器
  • vagrant 添加本地 box 安装 laravel homestead
  • vue 个人积累(使用工具,组件)
  • Vultr 教程目录
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 技术:超级实用的电脑小技巧
  • 京东美团研发面经
  • 微信开放平台全网发布【失败】的几点排查方法
  • 由插件封装引出的一丢丢思考
  • 智能网联汽车信息安全
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • # 利刃出鞘_Tomcat 核心原理解析(二)
  • #### go map 底层结构 ####
  • #Java第九次作业--输入输出流和文件操作
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • (1)(1.13) SiK无线电高级配置(五)
  • (1)Nginx简介和安装教程
  • (ZT)薛涌:谈贫说富
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (一)UDP基本编程步骤
  • (译)2019年前端性能优化清单 — 下篇
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET/C# 使用 #if 和 Conditional 特性来按条件编译代码的不同原理和适用场景
  • .net分布式压力测试工具(Beetle.DT)