孤舟笔记 并发篇三十 CompletableFuture到底是个啥?为什么说它是异步编程的王者
文章目录一、先说结论CompletableFuture vs Future二、从 Future 的痛点说起三、链式回调异步流水线四、任务组合112五、异常处理别让流水线崩盘CompletableFuture 全景回答技巧与点评标准回答加分回答面试官点评个人网站你写过异步代码吗那种先发请求等结果回来再处理的逻辑用 Future 写起来简直是噩梦——get() 阻塞住了、多个任务组合全靠手写、异常处理全靠 try-catch 包裹。面试官一问CompletableFuture 了解吗你就知道它是个升级版但具体好在哪、怎么用说不上来。今天咱们把 CompletableFuture 的设计思路、核心用法和常见坑彻底讲清楚。一、先说结论CompletableFuture vs Future维度FutureCompletableFuture异步回调❌ 只能阻塞 get()✅ thenApply/thenAccept 等链式回调任务组合❌ 不支持✅ thenCombine/allOf/anyOf异常处理❌ 只能 try-catch✅ exceptionally/handle手动完成❌ 不支持✅ complete(T value)非阻塞❌ get() 阻塞✅ 回调驱动不阻塞一句话记住Future 是点外卖一直等CompletableFuture 是点外卖留电话到了打给你。二、从 Future 的痛点说起Future 是 Java 5 引入的异步模型但用起来很憋屈FutureStringfutureexecutor.submit(()-{returnqueryFromDB();// 耗时操作});Stringresultfuture.get();// 阻塞干等着三个致命问题get() 阻塞——异步变成了伪异步主线程还是卡住了无法组合——查完数据库再调远程接口你得自己写嵌套回调无法手动完成——超时了想给个默认值做不到CompletableFuture 就是来解决这些痛点的Java 8 引入灵感来自 JavaScript 的 Promise。三、链式回调异步流水线CompletableFuture 最核心的能力是链式回调——一个任务完成自动触发下一个CompletableFuture.supplyAsync(()-queryUser(userId))// 1. 异步查用户.thenApply(user-queryOrder(user.id))// 2. 拿到用户后查订单 .thenAccept(order-sendEmail(order))// 3. 拿到订单后发邮件.exceptionally(ex-{// 4. 异常兜底log.error(出错了,ex);returnnull;});生活类比就像工厂流水线——第一个工人加工完自动传给下一个工人不需要每个工人都站在旁边等。关键方法方法作用参数类型thenApply转换结果有返回值FunctionthenAccept消费结果无返回值ConsumerthenRun不关心结果执行下一步RunnablethenCompose扁平化类似 flatMapFunctionT, CompletableFuturethenApply和thenCompose的区别就像map和flatMap——后者用于下一步也是异步任务的场景。四、任务组合112两个异步任务都完成后怎么处理CompletableFuture 提供了丰富的组合方式// 场景同时查用户信息和订单信息都拿到后合并CompletableFutureUseruserFuturesupplyAsync(()-getUser());CompletableFutureOrderorderFuturesupplyAsync(()-getOrder());// 两个都完成合并结果userFuture.thenCombine(orderFuture,(user,order)-{returnnewUserOrderVO(user,order);// 两个结果都能用});// 等所有任务完成CompletableFuture.allOf(future1,future2,future3).join();// 任一完成即可CompletableFuture.anyOf(future1,future2,future3).join();生活类比allOf像请客——所有人都到了才开饭anyOf像叫车——任何一辆车到了就走。五、异常处理别让流水线崩盘异步任务抛异常链式调用不会自动中断但你需要主动处理CompletableFuture.supplyAsync(()-riskyOperation()).thenApply(result-process(result)).exceptionally(ex-{// 捕获异常返回默认值log.error(失败了,ex);returndefaultValue;});// 或者用 handle 同时处理正常和异常.supplyAsync(()-riskyOperation()).handle((result,ex)-{if(ex!null)returndefaultValue;// 异常走这里returnprocess(result);// 正常走这里 });注意坑thenApply里抛的异常exceptionally能抓住但如果thenApply之后的thenAccept抛异常前面的exceptionally抓不到——异常处理要放在链的末端。CompletableFuture 全景CompletableFuture 全景 核心能力 ├── 链式回调 ── thenApply/thenAccept/thenCompose ├── 任务组合 ── thenCombine/allOf/anyOf ├── 异常处理 ── exceptionally/handle └── 手动完成 ── complete/completeExceptionally 创建方式 ├── supplyAsync ── 有返回值的异步任务 ├── runAsync ── 无返回值的异步任务 └── 已知值 ── completedFuture(value) 线程池 ├── 不指定 ── ForkJoinPool.commonPool()⚠️ 共享池 └── 指定 ── supplyAsync(supplier, executor) 口诀CompletableFuture 链式调异步回调不阻塞 组合 allOf 和 anyOf异常 handle 要兜底 线程池别用共享池生产环境要指定。回答技巧与点评标准回答CompletableFuture 是 Java 8 引入的异步编程工具实现了 Future 和 CompletionStage 接口。相比 Future它支持链式回调thenApply/thenAccept、任务组合thenCombine/allOf/anyOf、异常处理exceptionally/handle和手动完成complete。核心思想是回调驱动——任务完成后自动触发下一步不需要阻塞等待真正实现了非阻塞异步编程。加分回答CompletionStage 设计模式CompletableFuture 实现了 CompletionStage 接口这是流水线模式——每个方法返回新的 CompletableFuture形成链式调用。和 Stream API 的设计理念一脉相承都是函数式编程的思想线程池陷阱不指定线程池时使用 ForkJoinPool.commonPool()这是全局共享池所有 CompletableFuture 和并行流共用。生产环境必须指定独立线程池否则一个慢任务可能拖垮整个应用超时控制Java 9 增加了 orTimeout() 和 completeOnTimeout()补齐了超时处理能力。Java 8 中需要用 CompletableFuture.anyOf 配合 schedule 来模拟超时面试官点评这道题考的是你对异步编程模型的理解深度。能说出链式回调任务组合异常处理是基本要求能讲清楚 thenApply 和 thenCompose 的区别、线程池为什么要指定才算及格。如果你能提到 CompletionStage 接口的设计、commonPool 的生产风险、Java 9 的超时增强面试官会认为你不仅用过还在生产中踩过坑这是非常加分的。原文阅读内容有帮助点赞、收藏、关注三连评论区等你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2580112.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!