news 2026/6/9 14:31:33

详细分析Java8中的CompletableFuture异步编程类(附Demo)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
详细分析Java8中的CompletableFuture异步编程类(附Demo)

目录

  • 前言
  • 1. 基本知识
  • 2. Demo
  • 3. 实战

前言

Java基本知识:

  1. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  2. 【Java项目】实战CRUD的功能整理(持续更新)

1. 基本知识

CompletableFuture 是 Java 8 引入的异步编程类,属于 java.util.concurrent 包的一部分

  1. 异步计算(async computation)

  2. 事件驱动(callback)

  3. 任务组合(composition)

  4. 异常处理(exception handling)

核心思想是非阻塞地执行任务,并在任务完成后处理结果

核心特性

  • 非阻塞:与 Future.get() 阻塞不同,CompletableFuture 可以通过回调非阻塞地处理结果

  • 链式调用:可以通过方法链组合多个异步任务

  • 异常处理:提供 exceptionally、handle 等方法处理异常

  • 线程池支持:可以指定 Executor 来控制异步任务执行线程

常用的方法总结如下:

方法类型功能描述注意事项
runAsync(Runnable)创建异步执行无返回值任务默认使用 ForkJoinPool.commonPool(),任务无返回值
supplyAsync(Supplier<U>)创建异步执行有返回值任务默认使用 ForkJoinPool.commonPool()
thenApply(Function<? super T,? extends U>)转换对结果进行处理并返回新值上一个任务异常时不执行
thenAccept(Consumer<? super T>)消费对结果进行消费,无返回值上一个任务异常时不执行
thenRun(Runnable)消费上一个任务完成后执行,无结果传递上一个任务异常时不执行
thenCompose(Function<? super T,? extends CompletionStage<U>>)组合链式异步调用,顺序依赖可以避免嵌套CompletableFuture
thenCombine(CompletionStage<? extends U>, BiFunction<? super T,? super U,? extends V>)组合两个独立异步任务完成后合并结果两个任务都完成才执行
thenAcceptBoth(CompletionStage<? extends U>, BiConsumer<? super T,? super U>)组合两个独立任务完成后消费结果无返回值
runAfterBoth(CompletionStage<?> , Runnable)组合两个独立任务完成后执行,无结果传递无返回值
allOf(CompletableFuture<?>...)等待等待所有任务完成返回CompletableFuture<Void>,需自行获取每个结果
anyOf(CompletableFuture<?>...)等待任意一个任务完成即可返回CompletableFuture<Object>,需强转类型
exceptionally(Function<Throwable,? extends T>)异常处理捕获异常并返回默认值上游异常时触发
handle(BiFunction<? super T, Throwable, ? extends U>)异常处理对结果或异常处理无论异常与否都会执行
whenComplete(BiConsumer<? super T,? super Throwable>)异常处理对结果或异常进行观察,无返回值类似finally

核心方法:

创建:supplyAsync(), runAsync()
链式处理:thenApply(), thenAccept(), thenRun()
组合:thenCompose(), thenCombine(), allOf(), anyOf()
异常处理:exceptionally(), handle()

2. Demo

示例 1:异步任务执行

publicstaticvoiddemoRunAsync(){CompletableFuture.runAsync(()->{System.out.println("执行任务: "+Thread.currentThread().getName());}).join();}

示例 2:有返回值异步任务

publicstaticvoiddemoSupplyAsync(){intresult=CompletableFuture.supplyAsync(()->{return42;}).thenApply(x->x*2).join();System.out.println("结果: "+result);}

示例 3:组合两个任务

publicstaticvoiddemoThenCombine(){CompletableFuture<Integer>f1=CompletableFuture.supplyAsync(()->10);CompletableFuture<Integer>f2=CompletableFuture.supplyAsync(()->20);intsum=f1.thenCombine(f2,Integer::sum).join();System.out.println("组合结果: "+sum);}

示例 4:异常处理

publicstaticvoiddemoExceptionally(){CompletableFuture<Integer>future=CompletableFuture.supplyAsync(()->{if(true)thrownewRuntimeException("出错了");return100;});intresult=future.exceptionally(ex->{System.out.println("捕获异常: "+ex.getMessage());return-1;}).join();System.out.println("最终结果: "+result);}

示例 5:等待多个任务完成

publicstaticvoiddemoAllOf(){CompletableFuture<Integer>f1=CompletableFuture.supplyAsync(()->10);CompletableFuture<Integer>f2=CompletableFuture.supplyAsync(()->20);CompletableFuture<Integer>f3=CompletableFuture.supplyAsync(()->30);CompletableFuture<Void>all=CompletableFuture.allOf(f1,f2,f3);all.join();// 等待所有任务完成intsum=f1.join()+f2.join()+f3.join();System.out.println("总和: "+sum);}

大的一个Demo:

importjava.util.concurrent.*;publicclassCompletableFutureDemo{publicstaticvoidmain(String[]args)throwsException{ExecutorServiceexecutor=Executors.newFixedThreadPool(3);// 异步任务1CompletableFuture<Integer>future1=CompletableFuture.supplyAsync(()->{System.out.println("任务1执行线程: "+Thread.currentThread().getName());return10;},executor);// 异步任务2CompletableFuture<Integer>future2=CompletableFuture.supplyAsync(()->{System.out.println("任务2执行线程: "+Thread.currentThread().getName());return20;},executor);// 组合任务:任务1和任务2完成后求和CompletableFuture<Integer>resultFuture=future1.thenCombine(future2,(a,b)->a+b);// 处理结果和异常resultFuture.thenAccept(sum->System.out.println("结果: "+sum)).exceptionally(ex->{System.out.println("异常:"+ex.getMessage());returnnull;});// 等待所有任务完成resultFuture.join();executor.shutdown();}}

截图如下:

3. 实战

之所以有这个知识点,是因为我原先的异步写错了,导致有这个总结的思路

上述意思如下:

线程A: 算法1算法2算法3

实际应该如下:

线程A:算法1线程B:算法2线程C:算法3

实际如下:

AI 算法AFuture<TaskResult>AI 算法BFuture<TaskResult>AI 算法CFuture<TaskResult>↓ allOf 等待 ↓ 汇总结果给前端

大致的Demo如下:

publicclassAiRecognition{publicstaticStringTOKEN="xxx";// === 线程池(生产环境建议交给 Spring 管理)===privatestaticfinalExecutorServiceEXECUTOR=Executors.newFixedThreadPool(3);/** * 三个 AI 算法并发识别 */publicstaticCompletableFuture<AiCheckResult>aiCheckAll(StringimgUrlF,StringimgUrlL,StringimgUrlI){CompletableFuture<TaskResult>containerFuture=CompletableFuture.supplyAsync(()->safeContainerCheck(imgUrlF),EXECUTOR);CompletableFuture<TaskResult>doorFuture=CompletableFuture.supplyAsync(()->safeDoorCheck(imgUrlL),EXECUTOR);CompletableFuture<TaskResult>innerFuture=CompletableFuture.supplyAsync(()->safeInnerCheck(imgUrlI),EXECUTOR);returnCompletableFuture.allOf(containerFuture,doorFuture,innerFuture).thenApply(v->{List<TaskResult>list=Arrays.asList(containerFuture.join(),doorFuture.join(),innerFuture.join());AiCheckResultresult=newAiCheckResult();result.setDetails(list);result.setSuccess(list.stream().allMatch(TaskResult::isSuccess));returnresult;});}// === 以下是单个算法的安全封装 ===privatestaticTaskResultsafeContainerCheck(StringimgUrl){try{Stringdata=uploadImageAndRecognize(imgUrl,"http://xxxx");returnTaskResult.ok("containerNumber",data);}catch(Exceptione){returnTaskResult.fail("containerNumber",e.getMessage());}}privatestaticTaskResultsafeDoorCheck(StringimgUrl){try{Stringdata=uploadImageAndGetState(imgUrl,"http://xxxx");returnTaskResult.ok("doorState",data);}catch(Exceptione){returnTaskResult.fail("doorState",e.getMessage());}}privatestaticTaskResultsafeInnerCheck(StringimgUrl){try{Stringdata=uploadImageAndGetState(imgUrl,"http://xxxx");returnTaskResult.ok("innerState",data);}catch(Exceptione){returnTaskResult.fail("innerState",e.getMessage());}}}

1️⃣ 定义单个算法的返回结果

publicclassTaskResult{privateStringtaskName;privatebooleansuccess;privateStringdata;privateStringreason;publicstaticTaskResultok(StringtaskName,Stringdata){TaskResultr=newTaskResult();r.taskName=taskName;r.success=true;r.data=data;returnr;}publicstaticTaskResultfail(StringtaskName,Stringreason){TaskResultr=newTaskResult();r.taskName=taskName;r.success=false;r.reason=reason;returnr;}// getter / setter 省略}

2️⃣ 汇总返回给前端的结果

publicclassAiCheckResult{privatebooleansuccess;privateList<TaskResult>details;// getter / setter}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 4:58:13

需求接口人与研发接口人的职责分别是什么

需求接口人与研发接口人是连接“业务价值”与“技术实现”的两个核心枢纽。需求接口人&#xff08;通常是产品经理或业务分析师&#xff09;的核心职责是“定义”&#xff0c;即明确“做什么”和“为什么做”&#xff0c;他们对业务价值、需求优先级和用户体验负责。研发接口人…

作者头像 李华
网站建设 2026/5/28 17:47:05

基于大数据的短视频用户兴趣分析的设计与实现(程序+文档+讲解)

课题介绍在短视频平台精细化运营、个性化推荐需求下&#xff0c;传统用户兴趣分析存在 “维度单一、实时性差、精准度不足” 的痛点&#xff0c;基于大数据技术构建的短视频用户兴趣分析体系&#xff0c;整合用户行为数据、内容交互数据、环境数据等多源信息&#xff0c;实现用…

作者头像 李华
网站建设 2026/5/31 14:28:08

【最新2023】各省地区生产总值GDP 人均生产总值(人均GDP) 地区生产总值指数的 省级省份

【最新2023】各省地区生产总值GDP 人均生产总值(人均GDP) 地区生产总值指数的 省级省份 时间范围1999-2023年 人均生产总值指数(人均GDP指数) 包括一下: 人均生产总值(人均GDP) 各省地区生产总值GDP 人均生产总值指数(人均GDP指数) 地区生产总值指数 见图 说明:人均生产总值指…

作者头像 李华
网站建设 2026/5/29 1:13:01

医疗自动标注漏医生隐写症状 后来补NLP规则引擎才救回诊断准确率

&#x1f4dd; 博客主页&#xff1a;jaxzheng的CSDN主页 目录医疗数据科学&#xff1a;当Excel遇上心电图&#xff0c;我差点把医院整崩溃了 一、为什么说我是"数据界的急诊科医生" 二、那些年我在医疗数据里踩过的坑 三、那些让人拍案叫绝的医疗数据应用 四、给想入…

作者头像 李华
网站建设 2026/6/4 19:17:46

C 语言字符串函数超全解析

对于刚接触 C 语言的小伙伴来说&#xff0c;字符串函数就像 “字符处理的万能工具”&#xff0c;但用不好也容易踩坑。这篇内容会从 “核心逻辑→常用函数→避坑指南” 一步步讲&#xff0c;先懂底层、再学用法、最后避坑&#xff0c;保证通俗易懂&#xff5e; 一、先搞懂&…

作者头像 李华
网站建设 2026/5/30 19:36:45

海外仓签收入库环节怎么优化?海外仓入库流程优化方案(附TOPWMS实操)

在海外仓一件代发业务中&#xff0c;海外仓入库环节常被低估&#xff0c;但入库的问题直接影响到后续仓库的一系列操作。货物堆堵、SKU混乱、错发追责等入库乱象&#xff0c;并非单纯的管理疏忽&#xff0c;其根源在于缺乏一套系统化、标准化的流程管控体系。今天将根据我们的东…

作者头像 李华