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

(转)JUC系列之《CompletableFuture:Java异步编程的终极武器》

转自https://developer.aliyun.com/article/1684158引言一、为什么需要CompletableFuture二、核心概念Promise与异步任务三、创建CompletableFuture四、任务链式编排thenApply、thenAccept、thenRun五、组合多个FuturethenCompose与thenCombine六、多任务组合allOf与anyOf七、异常处理exceptionally与handle八、总结与最佳实践互动环节引言在传统的Java并发编程中我们使用Future来获取异步任务的执行结果。但它有一个致命的弱点获取结果会阻塞线程而且难以优雅地处理多个异步任务之间的依赖关系。想象一下这样的场景你需要调用三个不同的远程服务然后将它们的结果合并返回。如果用Future.get()你只能在每个调用后傻傻地等待性能极差。CompletableFuture的出现彻底改变了这一切它不仅是Future的增强版更是一个强大的异步编程工具允许你以声明式的风格构建复杂的异步任务流水线无需阻塞等待极大提升了程序的吞吐量和响应能力。一、为什么需要CompletableFuture传统Future的局限性阻塞获取结果get()方法是阻塞的调用它时线程只能等待无法在等待时执行其他有用工作。无法手动完成不能手动设置Future的结果或异常。无法链式处理很难表达“当一个任务完成后接着做另一件事”这样的逻辑。需要手动用get()获取结果后再提交新任务代码繁琐且易出错。无法组合多个Future合并多个异步任务的结果非常困难且不优雅。CompletableFuture的核心优势非阻塞回调提供了一系列方法如thenApply, thenAccept可以在任务完成后自动触发回调无需阻塞等待。手动完成可以手动设置结果或异常使任务完成。强大的链式编程支持将多个异步任务以链式流水线的方式组合起来。多任务组合可以轻松地等待所有任务完成allOf或等待任意一个任务完成anyOf。优雅的异常处理提供了专门的异常处理方法可以在异步链的任何阶段处理异常。简单说CompletableFuture让异步编程变得像搭积木一样简单直观。二、核心概念Promise与异步任务CompletableFuture实现了两个接口Future提供了异步计算的结果get(), isDone()等。CompletionStage代表了异步计算中的一个阶段Stage。一个阶段的完成可以触发另一个依赖阶段的执行。这才是CompletableFuture强大功能的源泉。你可以把它理解为一个Promise我给你一个承诺CompletableFuture对象将来某个时刻我会给你一个结果或一个异常。在这个承诺兑现之前你可以告诉它“结果出来后请接着做A然后再做B...”。三、创建CompletableFuture1. 使用runAsync和supplyAsync这是最常用的创建方式它们都会在ForkJoinPool.commonPool()默认的ForkJoin线程池中异步执行任务。import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class CreationExample { public static void main(String[] args) throws ExecutionException, InterruptedException { // 1. runAsync: 执行没有返回值的Runnable任务 CompletableFutureVoid future1 CompletableFuture.runAsync(() - { System.out.println(正在运行一个无返回值的异步任务...); sleep(1000); }); future1.get(); // 等待任务完成 // 2. supplyAsync: 执行有返回值的Supplier任务最常用 CompletableFutureString future2 CompletableFuture.supplyAsync(() - { System.out.println(正在运行一个有返回值的异步任务...); sleep(1000); return Hello, CompletableFuture!; }); // 阻塞获取结果 String result future2.get(); System.out.println(获取到的结果: result); } private static void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }提示这两个方法都有重载版本可以传入自定义的Executor来指定任务在哪个线程池中运行。四、任务链式编排thenApply、thenAccept、thenRun这是CompletableFuture最核心、最常用的功能。它允许你将多个任务串联起来形成一个异步流水线。类比就像在餐厅点餐。supplyAsync(() - 下单) - 后厨开始做菜返回一个Future代表将来的菜.thenApply(菜 - 切好的菜) - 对菜进行加工转换结果.thenAccept(切好的菜 - 装盘) - 消费结果但不产生新结果.thenRun(() - 擦桌子) - 不关心上一步的结果只在前一步完成后执行一个动作public class ChainingExample { public static void main(String[] args) { // 创建一个初始的异步任务 CompletableFuture.supplyAsync(() - { System.out.println(任务1: 查询用户ID - Thread.currentThread().getName()); sleep(500); return User123; }) // thenApply: 接收上一步的结果进行转换返回新值 .thenApply(userId - { System.out.println(任务2: 根据ID( userId )查询用户详情); sleep(500); return userId 的详细信息; }) // thenAccept: 接收上一步的结果进行消费不返回新值 .thenAccept(userDetail - { System.out.println(任务3: 发送用户详情( userDetail )到界面); }) // thenRun: 不关心上一步结果只在前序步骤完成后执行 .thenRun(() - { System.out.println(任务4: 所有操作已完成记录日志); }); // 主线程继续执行其他工作... System.out.println(主线程不会被阻塞可以继续做其他事); sleep(3000); // 等待异步任务链执行完毕 } }关键点异步执行默认情况下每个回调任务可能会在同一个线程或其他线程中执行取决于CompletableFuture的内部优化。可以使用thenApplyAsync等方法强制指定在新的异步线程中执行。非阻塞整个链条的构建是瞬间完成的不会阻塞主线程。五、组合多个FuturethenCompose与thenCombine1.thenCompose扁平化嵌套的Future用于解决“回调地狱”Callback Hell。当一个异步任务依赖另一个异步任务的结果时使用。// 假设我们有两个服务方法都返回CompletableFuture CompletableFutureString getUserDetail(String userId) { return CompletableFuture.supplyAsync(() - Detail of userId); } CompletableFutureDouble getCreditRating(String userDetail) { return CompletableFuture.supplyAsync(() - 99.5); } public void thenComposeExample() { // 不使用thenCompose会导致嵌套丑陋 // CompletableFutureCompletableFutureDouble badNesting getUserDetail(User123).thenApply(detail - getCreditRating(detail)); // 使用thenCompose: 扁平化结果 CompletableFutureDouble result getUserDetail(User123) .thenCompose(this::getCreditRating); // this::getCreditRating 等价于 detail - getCreditRating(detail) result.thenAccept(rating - System.out.println(用户信用分: rating)); }2.thenCombine合并两个独立Future的结果当两个互不依赖的异步任务都完成后需要对它们的结果进行合并处理时使用。public void thenCombineExample() { CompletableFutureDouble weightFuture CompletableFuture.supplyAsync(() - { sleep(500); return 65.5; // 体重 }); CompletableFutureDouble heightFuture CompletableFuture.supplyAsync(() - { sleep(800); return 1.75; // 身高 }); // 合并两个独立任务的结果 CompletableFutureDouble bmiFuture weightFuture.thenCombine(heightFuture, (weight, height) - { System.out.println(计算BMI体重: weight , 身高: height); return weight / (height * height); }); bmiFuture.thenAccept(bmi - System.out.println(您的BMI指数: bmi)); }六、多任务组合allOf与anyOf1.allOf等待所有任务完成当你需要并行执行多个独立任务并等待它们全部完成后再继续时使用。public void allOfExample() { CompletableFutureString future1 CompletableFuture.supplyAsync(() - {sleep(1000); return 结果1;}); CompletableFutureString future2 CompletableFuture.supplyAsync(() - {sleep(2000); return 结果2;}); CompletableFutureString future3 CompletableFuture.supplyAsync(() - {sleep(3000); return 结果3;}); CompletableFutureVoid allFutures CompletableFuture.allOf(future1, future2, future3); // allOf返回的Future在所有任务完成时完成但没有聚合结果 allFutures.thenRun(() - { // 此时所有任务都已完成可以安全地调用get()了不会阻塞 try { String result1 future1.get(); String result2 future2.get(); String result3 future3.get(); System.out.println(所有任务完成结果: result1 , result2 , result3); } catch (Exception e) { e.printStackTrace(); } }).join(); // 等待所有任务完成 }2.anyOf等待任意一个任务完成当你只需要多个任务中的任意一个完成时使用。public void anyOfExample() { CompletableFutureString future1 CompletableFuture.supplyAsync(() - {sleep(1000); return 快速结果;}); CompletableFutureString future2 CompletableFuture.supplyAsync(() - {sleep(5000); return 慢速结果;}); CompletableFutureObject winner CompletableFuture.anyOf(future1, future2); winner.thenAccept(result - System.out.println(最先完成的任务结果是: result)); // 输出: 最先完成的任务结果是: 快速结果 }七、异常处理exceptionally与handle在异步链中任何一步都可能抛出异常。CompletableFuture提供了优雅的方式来处理异常而不需要丑陋的try-catch块。1.exceptionally捕获异常并提供默认值类似于try-catch只在发生异常时被调用。public void exceptionallyExample() { CompletableFuture.supplyAsync(() - { if (true) { // 模拟一个错误 throw new RuntimeException(Oops! Something went wrong!); } return Success; }) .exceptionally(ex - { // 只有当异常发生时才会进入这个回调 System.err.println(哎呀出错了: ex.getMessage()); return Default Value; // 提供一个默认的恢复值 }) .thenAccept(result - System.out.println(最终结果: result)); // 输出: 最终结果: Default Value }2.handle无论成功或失败都会执行类似于try-catch-finally无论成功还是失败都会被调用并接收结果和异常两个参数。public void handleExample() { CompletableFuture.supplyAsync(() - { // 可能成功也可能失败 return Success; // throw new RuntimeException(Failed); }) .handle((result, ex) - { if (ex ! null) { // 处理异常情况 System.err.println(任务失败: ex.getMessage()); return Recovered from failure; } // 处理成功情况 System.out.println(任务成功结果为: result); return result.toUpperCase(); }) .thenAccept(finalResult - System.out.println(处理后的结果: finalResult)); }八、总结与最佳实践核心思想CompletableFuture将复杂的异步回调、任务编排和异常处理转变为声明式、函数式的链式调用代码更加清晰和易于维护。** vs 传统Future**它解决了Future.get()阻塞线程的问题提供了无比强大的任务组合能力。最佳实践指定自定义线程池默认使用ForkJoinPool.commonPool()在生产环境中强烈建议根据业务类型传入自定义的Executor以避免不同业务相互干扰或耗尽公共线程池。善用异常处理一定要在异步链的末尾或关键节点使用exceptionally或handle避免异常被悄无声息地吞掉。理解异步边界明确每个thenApply/thenAccept是在哪个线程上执行的默认与上一个任务相同使用Async后缀则不同。适用场景并行调用多个远程服务然后聚合结果。构建异步、非阻塞的响应式流程。处理复杂的、多步骤的异步业务逻辑。CompletableFuture是Java 8引入的最重要的并发工具之一它彻底改变了Java的异步编程模式是学习和开发现代高并发、高性能Java应用的必备利器。

相关文章:

(转)JUC系列之《CompletableFuture:Java异步编程的终极武器》

转自: https://developer.aliyun.com/article/1684158 引言一、为什么需要CompletableFuture?二、核心概念:Promise与异步任务三、创建CompletableFuture四、任务链式编排:thenApply、thenAccept、thenRun五、组合多个Future&…...

2026年淮安品牌设计企业口碑大揭秘!这份优秀企业TOP榜单你看过吗?

在淮安,品牌设计行业发展态势良好,众多企业在市场中各展风采。下面为大家揭秘2026年淮安口碑较好的品牌设计企业。行业现状近年来,淮安品牌设计行业发展迅速。行业报告显示,随着淮安经济的不断增长,越来越多的企业开始…...

让前厅更高效,让服务更暖心——HWT2.0酒店话务台,重构宾客体验新范式

在酒店运营的日常里,前厅工作人员常常面临着诸多困扰:会议酒店高峰期话务拥堵,VIP 来电无法及时响应;批量叫醒任务繁重,漏接、错接导致宾客投诉;房态与分机信息不同步,服务响应滞后;…...

探索 36G1 - 改进 critic - TOPSIS 算法及仿真实现

36G1-改进critic-TOPSIS 可进行matlab和python仿真程序通用也可“改进”,在多准则决策分析领域,critic - TOPSIS 是一种颇为有效的方法,今天咱们就来聊聊对它改进的那些事儿,并且看看在 Matlab 和 Python 中怎么实现仿真。 一、改…...

CodeFormer:基于代码本查找Transformer的AI人脸修复技术全解析

CodeFormer:基于代码本查找Transformer的AI人脸修复技术全解析 【免费下载链接】CodeFormer [NeurIPS 2022] Towards Robust Blind Face Restoration with Codebook Lookup Transformer 项目地址: https://gitcode.com/gh_mirrors/co/CodeFormer 技术原理&am…...

RVC模型参数详解与调优指南:如何获得最佳变声效果

RVC模型参数详解与调优指南:如何获得最佳变声效果 你是不是也遇到过这种情况:用RVC模型做变声,出来的声音要么音调怪怪的,像机器人,要么听起来完全不像目标音色,甚至还有杂音。明明跟着教程一步步来的&…...

Qt开源背后的那些秘密

程序员或者开源爱好者,你是不是经常听到“GPL”、“自由软件”、“开源协议”,但其实不太明白它们到底是什么?今天,我们来一次彻底解读,让你秒懂GPL,也顺便了解它和Qt开源许可的关系。GPL到底是什么&#x…...

安装docker后,一段时间后,ssh连不上

昨天还能正常 SSH 连接,今天失败🛠️ 分步排查与修复1. 先恢复网卡与网络在虚拟机内执行以下命令,重新启用网卡并获取 IP:# 启用 ens33 网卡 sudo ip link set ens33 up# 向 DHCP 服务器申请 IP(恢复昨天的网络配置&am…...

结构体struct和类class

一、结构体(struct)C 中的 struct(结构体)是一种自定义数据类型,核心作用是将不同类型但相关联的数据封装在一起,形成一个整体。它是 C 面向对象编程的基础之一(甚至可以看作轻量级的类&#xf…...

告别线束羁绊,重塑工业通讯:南京来可LCWLAN系列CAN转WiFi模块硬核揭秘

产品概述:打破线束羁绊,重塑工业通讯在复杂多变的工业现场与飞速发展的物联网时代,传统有线CAN总线正面临布线困难、移动设备受限以及跨网段数据孤岛等严峻挑战。如何让稳定可靠的CAN数据“飞”上云端,或在移动设备间无缝穿梭&…...

MyBatis Interceptor执行顺序详解(plugin机制、责任链模式)

目录一、引言二、Interceptor的注册顺序2.1 配置文件注册(mybatis-config.xml)2.2 代码注册2.3 SpringBoot Order2.4 扩展 - PageHelper链最后(即最先执行)三、plugin机制与InterceptorChain3.1 InterceptorChain.pluginAll3.2 In…...

2026大专电子商务毕业生就业学数据分析的价值分析

电子商务与数据分析的行业趋势近年来电子商务行业数据化转型加速,企业普遍依赖数据分析优化运营、精准营销和供应链管理。2025年《中国电子商务报告》显示,超75%的电商企业将数据分析能力列为核心岗位要求,涵盖用户行为分析、销售预测等场景。…...

“AI+”引爆家电新一轮以旧换新,AWE上看AI家电“百花争艳”

3月12日,以“AI科技,慧享未来”为主题的中国家电及消费电子博览会(AWE)在上海启幕,长虹携全线AI家电矩阵亮相,从画质革新的RGB-Mini LED新品、AI人感空调、场景化的AI冰洗厨套系,再到AI智慧家居…...

收藏!2026大模型春招真相|200个真实JD拆解,后端/算法转岗必看(小白友好)

本人从后端开发传统算法双赛道转岗大模型,最近趁着金三银四春招,计划冲刺一波大模型相关岗位,但越准备越迷茫——大模型知识点繁杂且更新极快,个人精力有限,始终找不到重点,不知道该把时间花在哪些技能上才…...

Win11家庭版也能用组策略?3步教你手动安装gpedit.msc(附完整CMD代码)

解锁Windows 11家庭版的隐藏管理能力:手动部署组策略编辑器全指南 如果你正在使用Windows 11家庭版,可能早就发现了一个令人困惑的“缺失”——在运行对话框里输入gpedit.msc,系统会告诉你找不到这个文件。这并非你的系统出了问题&#xff0c…...

Blender新手必看:3种超简单模型环绕技巧(附详细步骤图)

Blender新手必看:3种超简单模型环绕技巧(附详细步骤图) 刚接触Blender,面对空白的3D视窗,是不是既兴奋又有点无从下手?尤其是当你需要让一堆物体,比如柱子、灯泡、甚至是科幻场景中的能量核心&a…...

一灯即千言:无线Andon系统如何重塑服装厂敏捷生产

在传统服装制造车间,问题的发现与解决往往依赖班组的巡视与工人的主动汇报,信息流如同穿梭的线头,容易纠缠、迟滞。一个微小的断针、一道色差的缝线、一次设备的异常停顿,都可能因为信息传递的“时间差”而演变为整批货品的延误。…...

Canoe中panel面板关联系统变量

背景:在SystemVariables中加了变量,但在Panel设计面板中未找到变量,be like 如下实际原因:在Environment中SystemVariables中新增数据后,未重新保存退出,导致此原因...

ChatGLM-6B多语言扩展:实现中英混合对话

ChatGLM-6B多语言扩展:实现中英混合对话 1. 引言 ChatGLM-6B作为一款优秀的开源对话模型,原生支持中英双语能力,但在实际使用中,很多开发者发现模型在处理中英混合对话时表现不够理想。比如当你问"帮我写一段Python代码实现…...

清研电子荣获维科杯·OFweek 2025年度动力电池材料创新技术奖

2026 年 3 月 12 日,维科杯・OFweek 2025锂电行业年度评选颁奖典礼在香港亚洲国际博览馆隆重举办。近 300 个参评项目历经专家评审、网络投票、行业编辑三轮严苛筛选,清研电子凭借动力电池材料领域“技术颠覆 产业落地 生态赋能” 的全方位优势&#x…...

立创开源:基于STM32F030的1kHz SPWM简易电池内阻测试仪设计与实现

手把手教你DIY一个电池内阻测试仪:从原理到实战 最近在折腾一些锂电池项目,发现电池内阻这个参数特别重要。内阻大了,电池放电时发热就厉害,容量也虚。市面上的专业内阻测试仪动辄上千,对咱们爱好者来说有点下不去手。…...

Stable-Diffusion-V1-5 辅助工业设计:生成产品概念草图与外观方案

Stable-Diffusion-V1-5 辅助工业设计:生成产品概念草图与外观方案 1. 引言 你有没有过这样的经历?面对一个全新的产品设计任务,脑子里想法很多,但要把它们画出来,却感觉无从下笔。一张白纸,一支笔&#x…...

Phi-3 Forest Laboratory API接口调用全指南:从鉴权到流式响应

Phi-3 Forest Laboratory API接口调用全指南:从鉴权到流式响应 你是不是也对那些能对话、能写代码的AI模型感到好奇,想自己动手调用一下试试?今天咱们就来聊聊怎么通过代码,跟一个叫Phi-3 Forest Laboratory的模型“说上话”。别…...

Realistic Vision V5.1本地化部署教程:纯离线、零网络依赖、宽屏交互界面搭建

Realistic Vision V5.1本地化部署教程:纯离线、零网络依赖、宽屏交互界面搭建 想在自己的电脑上体验媲美单反相机的人像摄影效果,但又担心复杂的云端配置和网络依赖?今天,我们就来手把手教你,如何将顶级的Realistic V…...

磁链三矢量

磁链三矢量在电机控制的世界里,磁链三矢量就像三位配合默契的舞者。想象你手里有个三相电机,三个相位互相纠缠的磁场总让你头疼。这时候不妨试试把ABC坐标系拍扁——没错,我说的就是把三相电流投影到二维平面的αβ坐标系变换。先来看段硬核代…...

SPI 2026 报告解读—服务企业的竞争,正在从“拼业务”变成“拼管理”

每年 SPI Research 发布的《Professional Services Maturity Benchmark》,对于专业服务企业管理都是极具参考价值的一份报告。这份报告已经持续做了 19 年,几乎可以说是全球专业服务企业最系统的经营数据研究之一。2026年的报告基于 509家专业服务企业的…...

DrissionPage实战:绕过滑块验证的精准定位与模拟操作(非深度学习方案)

1. 为什么选择非深度学习的滑块验证绕过方案 最近在做一个自动化项目时,遇到了滑块验证码这个拦路虎。刚开始我也考虑过用深度学习方案,但实测下来发现几个痛点:首先需要大量标注数据训练模型,其次识别准确率不稳定,最…...

Nano-Banana高效部署教程:Docker镜像开箱即用,无需conda环境配置

Nano-Banana高效部署教程:Docker镜像开箱即用,无需conda环境配置 你是不是也遇到过这种情况?看到网上那些酷炫的产品拆解图、爆炸图,自己也想动手做一个,结果发现要装一堆环境,什么Python、PyTorch、各种依…...

JAVA实习生问:为什么项目不用VO?

校大网原创,公众号首发给刚开始的线上实习生做代码评审,发现有一个同学在返回给前端的Response DO 对象 里面,又额外套了一层 VO 对象。我就问他:“为什么要多加一层?没有任何逻辑的增加,就好像是脱裤子放屁…...

如何通过监控指标保障数据库连接池稳定性?动态数据源连接池问题诊断与优化实践

如何通过监控指标保障数据库连接池稳定性?动态数据源连接池问题诊断与优化实践 【免费下载链接】dynamic-datasource dynamic datasource for springboot 多数据源 动态数据源 主从分离 读写分离 分布式事务 项目地址: https://gitcode.com/gh_mirrors/dy/dynami…...