组合式异步编程

使用场景

有一定依赖关系的异步任务。

简单介绍

CompletableFuture,它是一个具体的类,实现了两个接口,一个是Future,另一个是CompletionStage。

Future表示异步任务的结果,而CompletionStage的字面意思是完成阶段。

多个CompletionStage可以以流水线的方式组合起来,对于其中一个CompletionStage,它有一个计算任务,但可能需要等待其他一个或多个阶段完成才能开始,它完成后,可能会触发其他阶段开始运行。

CompletionStage提供了大量方法,使用它们,可以方便地响应任务事件,构建任务流水线,实现组合式异步编程。

使用Future,我们只能通过get获取结果,而get可能会需要阻塞等待,而通过CompletionStage,可以注册回调函数,当任务完成或异常结束时自动触发执行。

Future/FutureTask使用Runnable或Callable表示任务,其中Runnable没有返回值,Callable有返回值。

CompletableFuture则使用Runnable和Supplier表示任务,其中Supplier代替了Callable表示有返回值,与Callable的区别是,它不能抛出受检异常,如果会发生异常,可以抛出运行时异常。

CompletableFuture是对Future的增强,但可以响应结果或异常事件,有很多方法构建异步任务流。

使用CompletableFuture,可以简洁自然地表达多个异步任务之间的依赖关系和执行流程,大大简化代码,提高可读性。

基本使用

CompletableFuture有Future的所有函数功能,除此之外还有如下一些功能:

函数

使用说明

supplyAsync

它接受两个参数supplier和executor,使用executor执行supplier表示的任务,返回一个CompletableFuture,调用后,任务被异步执行,这个方法立即返回。

runAsync

与上面类似,只是无需返回结果,即参数中的supplier换成了runnable。

join

等待任务结束,但它不会抛出受检异常。如果任务异常结束了,join会将异常包装为运行时异常CompletionException抛出。

getNow

与join类似,区别是,如果任务还没有结束,getNow不会等待,而是会返回传入的参数valueIfAbsent。

isCompletedExceptionally

判断任务是否是异常结束。

complete

在CompletableFuture中设置任务成功完成。

completeExceptionally

在CompletableFuture中设置任务异常结束,且附上具体异常。

whenComplete

  • 使用Future,我们只能通过get获取结果,而get可能会需要阻塞等待,而通过Com-pletionStage,可以注册回调函数,当任务完成或异常结束时自动触发执行。
  • 参数action表示回调函数,不管前一个阶段是正常结束还是异常结束,它都会被调用,函数类型是BiConsumer,接受两个参数,第一个参数是正常结束时的结果值,第二个参数是异常结束时的异常,BiConsumer没有返回值。
  • whenComplete的返回值还是CompletableFuture,它不会改变原阶段的结果,还可以在其上继续调用其他函数。

handle

同whenComplete类似,区别是handle回调函数是一个BiFunction,也是接受两个参数,一个是正常结果,另一个是异常,但BiFunction有返回值,在handle返回的CompletableFuture中,结果会被BiFunction的返回值替代,即使原来有异常,也会被覆盖。

exceptionally

  • whenComplete和handle都是既响应正常完成也响应异常,如果只对异常感兴趣,可以使用exceptionally。
  • 它注册的回调函数是Function,接受的参数为异常,返回一个值,与handle类似,它也会改变结果。

任务流

使用CompletableFuture,可以方便地构建有多种依赖关系的任务流。

thenRun

  • 在一个阶段正常完成后,执行下一个任务。
  • 在thenRun构建的任务流中,只有前一个阶段没有异常结束,下一个阶段的任务才会执行,如果前一个阶段发生了异常,所有后续阶段都不会运行,结果会被设为相同的异常,调用join会抛出运行时异常CompletionException。
  • thenRun指定的下一个任务类型是Runnable,它不需要前一个阶段的结果作为参数,也没有返回值,所以,在thenRun返回的CompletableFuture中,结果类型为Void,即没有结果。

thenAccept/thenApply

  • 与thenRun功能类似,不同的是可以为下一个任务提供前一个阶段的结果作为参数。
  • thenAccept的任务类型是Consumer,它接受前一个阶段的结果作为参数,没有返回值。
  • thenApply的任务类型是Function,接受前一个阶段的结果作为参数,返回一个新的值,这个值会成为thenApply返回的CompletableFuture的结果值。

thenCompose

与thenApply类似,不同的是这个转换函数fn的返回值类型是CompletionStage,也就是说,它的返回值也是一个阶段。thenCompose与thenApply的区别就如同Stream API中flatMap与map的区别。

runAfterBoth

thenCombine

thenAcceptBoth

  • runAfterBoth对应的任务类型是Runnable。
  • thenCombine对应的任务类型是BiFunction,接受前两个阶段的结果作为参数,返回一个结果。
  • thenAcceptBoth对应的任务类型是BiConsumer,接受前两个阶段的结果作为参数,但不返回结果。
  • 当前阶段和参数指定的另一个阶段other没有依赖关系,并发执行,当两个都执行结束后,开始执行指定的另一个任务。

runAfterEither

applyToEither

acceptEither

上面三个函数要求两个阶段都完成后才执行下一个任务,如果只需要其中任意一个阶段完成,可以使用这三个方法。

allOf

  • 基于多个CompletableFuture构建了一个新的CompletableFuture。
  • 当所有子CompletableFuture都完成时,它才完成,如果有的Completable-Future异常结束了,则新的CompletableFuture的结果也是异常。
  • 不会因为有异常就提前结束,而是会等待所有阶段结束,如果有多个阶段异常结束,新的Com-pletableFuture中保存的异常是最后一个的。
  • 新的CompletableFuture会持有异常结果,但不会保存正常结束的结果,如果需要,可以从每个阶段中获取。

anyOf

  • 当第一个子CompletableFuture完成或异常结束时,它相应地完成或异常结束,结果与第一个结束的子CompletableFuture一样。

CompletableFuture中有很多名称带有run、accept或apply的方法,它们一般与任务的类型相对应:

  • run        ->  Runnable
  • accept  -> Consumer
  • apply    ->  Function

根据任务由谁执行,一般有三类对应方法:

  • 名称不带Async的方法由当前线程或前一个阶段的线程执行
  • 带Async但没有指定Executor的方法由默认Excecutor(Fork-JoinPool.commonPool()或ThreadPerTaskExecutor)执行
  • 带Async且指定Executor参数的方法由指定的Executor执行

#函数式编程##java原理#
Java知识专辑 文章被收录于专栏

知其然知其所以然,只有掌握了底层原理,借助第一性原理,才可以在日常开发和项目中运用自如,潇洒走江湖。

全部评论
题2:https://www.nowcoder.com/discuss/860135735427371008
点赞 回复 分享
发布于 03-08 12:33 上海
题1:https://www.nowcoder.com/discuss/860135125781106688
点赞 回复 分享
发布于 03-08 12:33 上海

相关推荐

在实习生的社交礼仪里,团建本该是刷脸、融入的大好机会。但我没在那场团建里刷出好感,反而刷出了我职业生涯的第一个“至暗时刻”。那天小组团建,本以为就是大家吃吃喝喝、闲聊吐槽,结果环节设置里偏偏有个竞技类的互动游戏。作为一个运动细胞约等于零、反应力在高度紧张下直接降为负数的社恐,我站在那一刻,就预感到大事不妙。果然,怕什么来什么。那个环节需要组员之间高度配合,而我恰好被安排在了决定胜负的关键位。因为我一个动作的迟钝和判断失误,我们小组那本该稳拿的第一名,就在我手里眼睁睁地飞走了。最尴尬的不是输了,而是输了之后全场那一秒钟的寂静。虽然组里的哥哥姐姐们人都很好,大家反应过来后立马开始打圆场,笑着说“没事没事,重在参与”,或者“晚饭多吃点补回来”。但我当时低着头,脸烫得能煮鸡蛋。那种“因为我一个人,导致全组人的努力白费”的愧疚感,像潮水一样把我淹没了。在那之后的几个小时里,我觉得自己就像个透明人,哪怕别人跟我说话,我也总觉得大家在心里默默复盘刚才那个被我搞砸的瞬间。那种尴尬,不是丢脸那么简单,而是一种深深的“不合群感”。在职场这个强调团队协作的地方,第一次意识到自己成了那个“短板”,那种挫败感真的让人想原地消失。后来我也想通了,其实大家可能转头就忘了谁输谁赢,只有自己还在那儿反复自省。但那个下午,那个因为我一个人的失误导致全组输掉的瞬间,绝对是我实习期里最想格式化的记忆。
实习生至暗时刻
点赞 评论 收藏
分享
03-10 10:43
浙江大学
📋 今日校招速递,以下企业近1天内有2026春招/校招动态:1️⃣ 中国中车 — 2026届春季校园招聘正式启动全球轨道交通装备龙头央企,3000+岗位,涵盖电气自动、机械车辆、电子信息、计算机、材料、管理等方向🔗 https://crrc.hotjob.cn/2️⃣ 中广核 — 2026届春季校园招聘启动核能+新能源央企,覆盖七大产业板块,25/26届均可报名🔗 https://cgn.hotjob.cn/3️⃣ 东风汽车 — 2026春季全球校园招聘大型央企车企,2000+岗位,智能网联/新能源/大数据等方向,武汉/十堰/襄阳/广州等多城🔗 https://dfmc.hotjob.cn/4️⃣ 比亚迪 — 2026届春季校园招聘新能源汽车龙头,研发/制造/管理等岗位,深圳总部+全国多基地🔗 https://job.byd.com/5️⃣ 恒生电子 — 2026春季校园招聘(4月2日前报名)金融科技头部企业,Fintech100全球百强,杭州总部,软件开发/测试/金融等岗位🔗 https://campus.hundsun.com/6️⃣ 得物 — 2026年春季校园招聘启动潮流电商平台,技术/产品/运营/设计等岗位,上海/杭州🔗 https://campus.dewu.com/7️⃣ 学而思 — 2026春季校园招聘启动教育科技企业,500+校招及实习岗位,教学/研发/运营/市场🔗 https://xueersi.zhiye.com/💡 金三银四春招季,抓紧网申!以上链接均为企业官方招聘网站,长期有效。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务