CompletableFuture高级模式详解
目录
CompletableFuture高级模式详解
1. CompletableFuture基础概念
1.1 什么是CompletableFuture?
1.2 异步编程基础
1.3 CompletableFuture与Future的对比
2. 创建CompletableFuture
2.1 基本创建方法
2.2 使用异步方法创建
2.3 指定执行器
3. 转换和链式操作
3.1 thenApply - 转换结果
3.2 thenAccept - 消费结果
3.3 thenRun - 执行后续操作
3.4 异步转换操作
4. 组合多个CompletableFuture
4.1 thenCompose - 顺序组合
4.2 thenCombine - 并行组合
4.3 allOf - 等待所有完成
4.4 anyOf - 等待任一完成
5. 异常处理
5.1 exceptionally - 简单异常处理
5.2 handle - 处理结果和异常
5.3 whenComplete - 不改变结果的监听
6. 超时处理
6.1 使用orTimeout方法(Java 9+)
6.2 使用completeOnTimeout方法(Java 9+)
6.3 Java 8中的超时处理
7. 异步执行与线程池
7.1 CompletableFuture默认线程池
7.2 自定义线程池
7.3 异步方法与线程池
8. 高级模式与实战案例
8.1 优雅的API调用模式
8.2 并行任务处理模式
8.3 重试模式
8.4 依赖关系处理模式
9. 最佳实践与常见陷阱
9.1 最佳实践
9.2 常见陷阱
10. 小结
进一步学习资源
1. CompletableFuture基础概念
1.1 什么是CompletableFuture?
CompletableFuture 是Java 8引入的一个类,实现了 Future 和 CompletionStage 接口,提供了一种更加强大和灵活的方式来进行异步编程。它解决了传统 Future 的多个限制:
- 传统
Future不能手动完成 - 传统
Future不支持链式操作 - 传统
Future没有提供异常处理机制
1.2 异步编程基础
异步编程允许程序在执行耗时操作时不阻塞主线程,提高程序的响应性和性能。异步编程的核心概念:
- 非阻塞操作:调用后立即返回,不等待执行完成
- 回调机制:任务完成后执行特定的代码
- 并行执行:多个任务同时执行
- 事件驱动:基于事件的处理模型
1.3 CompletableFuture与Future的对比
| 特性 | Future | CompletableFuture |
|---|---|---|
| 手动完成 | ❌ | ✅ |
| 链式操作 | ❌ | ✅ |
| 异常处理 | ❌ | ✅ |
| 组合多个Future | ❌ | ✅ |
| 超时处理 | 需要额外代码 | 内置支持 |
| 回调函数 | ❌ | ✅ |
2. 创建CompletableFuture
2.1 基本创建方法
// 创建一个空的CompletableFuture
CompletableFuture<String> future = new CompletableFuture<>();// 手动完成一个Future
future.complete("结果");// 创建一个已完成的Future
CompletableFuture<String> completedFuture = CompletableFuture.completedFuture("已完成");
2.2 使用异步方法创建
// 不返回结果的异步任务
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {System.out.println("异步任务在执行中...");// 执行耗时操作
});// 返回结果的异步任务
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("异步任务在执行中...");// 执行耗时操作return "操作结果";
});
2.3 指定执行器
ExecutorService executor = Executors.newFixedThreadPool(5);// 使用自定义线程池执行异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {System.out.println("使用自定义线程池: " + Thread.currentThread().getName());return "操作结果";
}, executor);
3. 转换和链式操作
3.1 thenApply - 转换结果
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");// 转换结果,String -> String
CompletableFuture<String> future2 = future.thenApply(s -> s + " World");// 转换结果,String -> Integer
CompletableFuture<Integer> future3 = future.thenApply(String::length);
3.2 thenAccept - 消费结果
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello").thenAccept(s -> System.out.println("得到结果: " + s));
// 不返回结果,仅执行操作
3.3 thenRun - 执行后续操作
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello").thenRun(() -> System.out.println("操作完成"));
// 不接收参数,也不返回结果
3.4 异步转换操作
// 异步执行thenApply
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello").thenApplyAsync(s -> {System.out.println("转换操作线程: " + Thread.currentThread().getName());return s + " World";});// 异步执行thenAccept
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> "Hello").thenAcceptAsync(s -> {System.out.println("消费操作线程: " + Thread.currentThread().getName());System.out.println("得到结果: " + s);});
4. 组合多个CompletableFuture
4.1 thenCompose - 顺序组合
CompletableFuture<String> getUserInfo(String userId) {return CompletableFuture.supplyAsync(() -> "用户信息: " + userId);
}CompletableFuture<String> getOrderInfo(String userInfo) {return CompletableFuture.supplyAsync(() -> userInfo + " 的订单");
}// 串行执行两个异步操作,第二个操作依赖第一个操作的结果
CompletableFuture<String> result = getUserInfo("12345").thenCompose(this::getOrderInfo);
4.2 thenCombine - 并行组合
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");// 并行执行两个异步操作,并合并它们的结果
CompletableFuture<String> result = future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2);
4.3 allOf - 等待所有完成
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "任务1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "任务2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "任务3");// 等待所有任务完成
CompletableFuture<Void> allDone = CompletableFuture.allOf(future1, future2, future3);// 等待完成后获取所有结果
CompletableFuture<List<String>> results = allDone.thenApply(v -> {return Stream.of(future1, future2, future3).map(CompletableFuture::join) // join不会抛出检查异常.collect(Collectors.toList());
});
4.4 anyOf - 等待任一完成
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "任务1";
});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return "任务2";
});// 任一任务完成即完成
CompletableFuture<Object> anyResult = CompletableFuture.anyOf(future1, future2);
5. 异常处理
5.1 exceptionally - 简单异常处理
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (Math.random() > 0.5) {throw new RuntimeException("操作失败");}return "操作成功";
}).exceptionally(ex -> {System.out.println("异常: " + ex.getMessage());return "默认值"; // 出现异常时返回默认值
});
5.2 handle - 处理结果和异常
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (Math.random() > 0.5) {throw new RuntimeException("操作失败");}return "操作成功";
}).handle((result, ex) 相关文章:
CompletableFuture高级模式详解
目录 CompletableFuture高级模式详解 1. CompletableFuture基础概念 1.1 什么是CompletableFuture? 1.2 异步编程基础 1.3 CompletableFuture与Future的对比 2. 创建CompletableFuture 2.1 基本创建方法 2.2 使用异步方法创建 2.3 指定执行器 3. 转换和链式操作 3.…...
【AI开源大模型工具链ModelEngine】【01】应用框架-源码编译运行
ModelEngine提供从数据处理、知识生成,到模型微调和部署,以及RAG(Retrieval Augmented Generation)应用开发的AI训推全流程工具链。 GitCode开源地址:https://gitcode.com/ModelEngineGitee开源地址:https…...
linux下截图工具的选择
方案一 gnome插件Screenshot Tool(截屏) ksnip(图片标注) gnome setting设置图片的默认打开方式为ksnip就可以快捷的将Screenshot Tool截屏的图片打开进行标记了。 但是最近我发现Screenshot Tool的延迟截图功能是有问题的&…...
每天记录一道Java面试题---day36
事务的基本特性和隔离级别 回答重点 事务基本特性ACID分别是: - 原子性指的是一个事务中的操作要么全部成功,要么全部失败。 - 一致性指的是数据库总是一个一致性的状态转换到另一个一致性的状态。比如A转账给B100块钱,假设A只有 90块&…...
Qt音频采集:QAudioInput详解与示例
1. 简介 QAudioInput是Qt Multimedia模块中用于音频采集的核心类,能够从麦克风等输入设备实时获取原始音频数据(PCM格式)。本文将通过原理讲解和代码示例,帮助开发者快速掌握音频采集的核心技术。 2. 核心功能 支持多种音频格式&…...
rkmpp 解码 精简mpi_dec_test.c例程
rkmpp 解码流程(除 MPP_VIDEO_CodingMJPEG 之外) 源码 输入h264码流 输出nv12文件 /** Copyright 2015 Rockchip Electronics Co. LTD** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file exce…...
怎么构造思维链数据?思维链提示工程的五大原则
我来为您翻译这篇关于思维链提示工程的文章,采用通俗易懂的中文表达: 思维链(CoT)提示工程是生成式AI(GenAI)中一种强大的方法,它能让模型通过逐步推理来解决复杂任务。通过构建引导模型思考过程的提示,思维链能提高输出的准确性…...
网络安全之-信息收集
域名收集 域名注册信息 站长之家 https://whois.chinaz.com/ whois 查询的相关网站有:中国万网域名WHOIS信息查询地址: https://whois.aliyun.com/西部数码域名WHOIS信息查询地址: https://whois.west.cn/新网域名WHOIS信息查询地址: http://whois.xinnet.com/domain/whois/in…...
JdbcTemplate基本使用
JdbcTemplate概述 它是spring框架中提供的一个对象,是对原始繁琐的JdbcAPI对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和MbernateTemplate,操作nosql数据库的RedisTemplate,操作消息队列的…...
pnpm 中 Next.js 模块无法找到问题解决
问题概述 项目在使用 pnpm 管理依赖时,出现了 “Cannot find module ‘next/link’ or its corresponding type declarations” 的错误。这是因为 pnpm 的软链接机制在某些情况下可能导致模块路径解析问题。 问题诊断 通过命令 pnpm list next 确认项目已安装 Next.js 15.2.…...
openEuler24.03 LTS下安装Spark
目录 安装模式介绍 下载Spark 安装Local模式 前提条件 解压安装包 简单使用 安装Standalone模式 前提条件 集群规划 解压安装包 配置Spark 配置Spark-env.sh 配置workers 分发到其他机器 启动集群 简单使用 关闭集群 安装YARN模式 前提条件 解压安装包 配…...
蓝桥杯真题——接龙序列
蓝桥杯2023年第十四届省赛真题-接龙数列 题目描述 对于一个长度为 K 的整数数列:A1, A2, . . . , AK,我们称之为接龙数列当且仅当 Ai 的首位数字恰好等于 Ai−1 的末位数字 (2 ≤ i ≤ K)。 例如 12, 23, 35, 56, 61, 11 是接龙数列;12, 2…...
使用 DeepSeek API 实现新闻文章地理位置检测与地图可视化
使用 DeepSeek API 实现新闻文章地理位置检测与地图可视化 | Implementing News Article Location Detection and Map Visualization with DeepSeek API 作者:zhutoutoutousan | Author: zhutoutoutousan 发布时间:2025-04-08 | Published: 2025-04-08 标…...
如何精准控制大模型的推理深度
论文标题 ThinkEdit: Interpretable Weight Editing to Mitigate Overly Short Thinking in Reasoning Models 论文地址 https://arxiv.org/pdf/2503.22048 代码地址 https://github.com/Trustworthy-ML-Lab/ThinkEdit 作者背景 加州大学圣迭戈分校 动机 链式推理能显…...
【力扣hot100题】(078)跳跃游戏Ⅱ
好难啊,我愿称之为跳崖游戏。 依旧用了两种方法,一种是我一开始想到的,一种是看答案学会的。 我自己用的方法是动态规划,维护一个数组记录到该位置的最少步长,每遍历到一个位置就嵌套循环遍历这个位置能到达的位置&a…...
Leetcode 34.在排序数组中查找元素的第一个和最后一个位置
题目描述 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target,返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 考察二…...
LangChain入门指南:调用DeepSeek api
文章目录 1. 什么是LangChain?2. 核心组件3. 为什么选择LangChain?4. 实战案例安装简单chat案例流式交互Prompt模板 5. 简单总结 1. 什么是LangChain? 定义:LangChain是一个用于构建大语言模型(LLM)应用的…...
WES与WGS数据线粒体DNA数据分析及检测工具
1. 线粒体DNA的异质性 传统的全外显子组测序(WES)和全基因组测序(WGS)的二代测序(SGS) 数据分析流程,能够识别多种类型的基因改变。但大多数用于基因变异分析和注释的工具,在输出文…...
word表格间隔设置
1.怎么解决word表格间隔达不到我们想要的要求 其实很简单, 我们直接在word表格里面, 全选表格中里面的内容。接着,我们选择自动调整---->根据内容自动调整表格,即可达到我们想要的要求...
SpringBoot 接口限流Lua脚本接合Redis 服务熔断 自定义注解 接口保护
介绍 Spring Boot 接口限流是防止接口被频繁请求而导致服务器负载过重或服务崩溃的一种策略。通过限流,我们可以控制单位时间内允许的请求次数,确保系统的稳定性。限流可以帮助防止恶意请求、保护系统资源,并优化 API 的可用性,避…...
设计模式 --- 观察者模式
设计模式 --- 观察者模式 什么是观察者模式观察者模式典型应用 --- C#中的事件使用观察者模式实现事件处理机制 什么是观察者模式 观察者模式(Observer Pattern)是一种行为型设计模式,用于在对象之间建立一对多的依赖关系。当一个对象&#x…...
电商核心指标解析与行业趋势:数据驱动的增长策略【大模型总结】
电商核心指标解析与行业趋势:数据驱动的增长策略 在电商领域,数据是决策的核心。从流量监测到用户行为分析,从价格策略到技术赋能,每一个环节的优化都离不开对核心指标的深度理解。本文结合行业最新趋势与头部平台实践࿰…...
I/O进程4
day4 九、信号灯集 1.概念 信号灯(semaphore),也叫信号量。它是不同进程间或一个给定进程内部不同线程间同步的机制;System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。 通过信号灯集实现共享内存的同步操作。 2.编程…...
【语法】C++的list
目录 为什么会有list? 迭代器失效: list和vector的迭代器不同的地方: list的大部分用法和vector都很像,例如push_back,构造,析构,赋值重载这些就不再废话了,本篇主要讲的是和vecto…...
【算法笔记】并查集详解
🚀 并查集(Union-Find)详解:原理、实现与优化 并查集(Union-Find)是一种非常高效的数据结构,用于处理动态连通性问题,即判断若干个元素是否属于同一个集合,并支持集合合…...
【Ai/Agent】Windows11中安装CrewAI过程中的错误解决记录
CrewAi是什么,可以看之下之前写的 《初识CrewAI多智能代理团队协框架》 (注:这篇是基于linux系统下安装实践的) 基于以下记录解决问题后,可以再回到之前的文章继续进行CrewAI的安装 遇到问题 在windows系统中安装 CrewAi 不管是使用 pip 或者…...
OSPF的数据报文格式【复习篇】
OSPF协议是跨层封装的协议(跨四层封装),直接将应用层的数据封装在网络层协议之后,IP协议包中协议号字段对应的数值为89 OSPF的头部信息: 所有的数据共有的信息字段 字段名描述版本当前OSPF进程使用的版本(…...
[leetcode]查询区间内的所有素数
一.暴力求解 #include<iostream> #include<vector> using namespace std; vector<int> result; bool isPrime(int i) { if (i < 2) return false; for (int j 2;j * j < i;j) { if (i % j 0) { …...
【力扣刷题实战】Z字形变换
大家好,我是小卡皮巴拉 文章目录 目录 力扣题目:Z字形变换 题目描述 解题思路 问题理解 算法选择 具体思路 解题要点 完整代码(C) 兄弟们共勉 !!! 每篇前言 博客主页:小卡…...
【RK3588 嵌入式图形编程】-SDL2-扫雷游戏-添加地雷到网格
添加地雷到网格 文章目录 添加地雷到网格1、概述2、更新Globals.h3、在随机单元格中放置地雷4、更新单元格以接收地雷5、渲染地雷图像6、开发助手7、完整代码8、总结在本文中,我们将更新游戏以在网格中随机放置地雷,并在单元格被清除时渲染它们。 1、概述 在我们扫雷游戏教程…...
