【多线程】Future相关
参考:
https://tech.meituan.com/2022/05/12/principles-and-practices-of-completablefuture.html
https://blog.csdn.net/u014209205/article/details/80598209
全网最全的CompletableFuture使用教程_ 25分钟掌握completablefuture的用法(含用法思维导图、样例,待补充到博客中) https://www.bilibili.com/video/BV1pk4y1u7fc/?spm_id_from=333.337.search-card.all.click
一、Future接口
Future用于表示异步计算的结果,只能通过阻塞或者轮询的方式获取结果,而且不支持设置回调方法,
核心方法:
所有已知实现类:CompletableFuture , CountedCompleter , ForkJoinTask , FutureTask , RecursiveAction , RecursiveTask , SwingWorker
All Known Subinterfaces: Response <T>, RunnableFuture <V>, RunnableScheduledFuture <V>, ScheduledFuture <
guava的ListenableFuture
Java 8之前若要设置回调一般会使用guava的ListenableFuture,回调的引入又会导致臭名昭著的回调地狱(下面的例子会通过ListenableFuture的使用来具体进行展示)

ExecutorService executor = Executors.newFixedThreadPool(5); ListeningExecutorService guavaExecutor = MoreExecutors.listeningDecorator(executor); ListenableFuture<String> future1 = guavaExecutor.submit(() -> { //step 1 System.out.println("执行step 1"); return "step1 result"; }); ListenableFuture<String> future2 = guavaExecutor.submit(() -> { //step 2 System.out.println("执行step 2"); return "step2 result"; }); ListenableFuture<List<String>> future1And2 = Futures.allAsList(future1, future2); Futures.addCallback(future1And2, new FutureCallback<List<String>>() { @Override public void onSuccess(List<String> result) { System.out.println(result); ListenableFuture<String> future3 = guavaExecutor.submit(() -> { System.out.println("执行step 3"); return "step3 result"; }); Futures.addCallback(future3, new FutureCallback<String>() { @Override public void onSuccess(String result) { System.out.println(result); } @Override public void onFailure(Throwable t) { } }, guavaExecutor); } @Override public void onFailure(Throwable t) { }}, guavaExecutor);
CompletableFuture的实现如下:更为简洁,可读性更好

ExecutorService executor = Executors.newFixedThreadPool(5); CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> { System.out.println("执行step 1"); return "step1 result"; }, executor); CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> { System.out.println("执行step 2"); return "step2 result"; }); cf1.thenCombine(cf2, (result1, result2) -> { System.out.println(result1 + " , " + result2); System.out.println("执行step 3"); return "step3 result"; }).thenAccept(result3 -> System.out.println(result3));
二、CompletableFuture
- 可组合:可以将多个依赖操作通过不同的方式进行编排,例如CompletableFuture提供thenCompose、thenCombine等各种then开头的方法,这些方法就是对“可组合”特性的支持。
- 操作融合:将数据流中使用的多个操作符以某种方式结合起来,进而降低开销(时间、内存)。
- 延迟执行:操作不会立即执行,当收到明确指示时操作才会触发。例如Reactor只有当有订阅者订阅时,才会触发操作。
- 回压:某些异步阶段的处理速度跟不上,直接失败会导致大量数据的丢失,对业务来说是不能接受的,这时需要反馈上游生产者降低调用量。
CompletableFuture实现了两个接口(如上图所示):Future、CompletionStage。
- Future:表示异步计算的结果,
- CompletionStage:表示异步执行过程中的一个步骤(Stage),这个步骤可能是由另外一个CompletionStage触发的,随着当前步骤的完成,也可能会触发其他一系列CompletionStage的执行。可以根据实际业务对这些步骤进行多样化的编排组合,CompletionStage接口正是定义了这样的能力,我们可通过thenAppy、thenCompose等函数式编程方法来组合编排这些步骤。
关键方法:
- CompletableFuture的创建
ExecutorService executor = Executors.newFixedThreadPool(5); //1、使用runAsync或supplyAsync发起异步调用 CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> { return "result1"; }, executor);
//2、CompletableFuture.completedFuture()直接创建一个已完成状态的CompletableFuture CompletableFuture<String> cf2 = CompletableFuture.completedFuture("result2");
//3、先初始化一个未完成的CompletableFuture,然后通过complete()、completeExceptionally(),完成该CompletableFuture CompletableFuture<String> cf = new CompletableFuture<>(); cf.complete("success");
在使用CompletableFuture类在进行线程管理时,通常会使用四个静态方法来为一段异步执行的代码创建CompletableFuture对象,
- 一元依赖:
CompletableFuture<String> cf3 = cf1.thenApply(result1 -> { //result1为CF1的结果 //...... return "result3"; }); CompletableFuture<String> cf5 = cf2.thenApply(result2 -> { //result2为CF2的结果 //...... return "result5"; });
- 二元依赖:thenCombine:CF4同时依赖于两个CF1和CF2
CompletableFuture<String> cf4 = cf1.thenCombine(cf2, (result1, result2) -> { //result1和result2分别为cf1和cf2的结果 return "result4"; });
多元依赖:
allOf
或anyOf:
整个流程的结束依赖于三个步骤CF3、CF4、CF5,这种多元依赖可以通过allOf
或anyOf
方法来实现,区别是当需要多个依赖全部完成时使用allOf
,当多个依赖中的任意一个完成即可时使用anyOf
CompletableFuture<Void> cf6 = CompletableFuture.allOf(cf3, cf4, cf5); CompletableFuture<String> result = cf6.thenApply(v -> { //这里的join并不会阻塞,因为传给thenApply的函数是在CF3、CF4、CF5全部完成时,才会执行 。 result3 = cf3.join(); result4 = cf4.join(); result5 = cf5.join(); //根据result3、result4、result5组装最终result; return "result"; });
- 异常处理:CompletableFuture提供了异常捕获回调exceptionally,相当于同步调用中的try\catch。使用方法如下所示:
@Autowired private WmOrderAdditionInfoThriftService wmOrderAdditionInfoThriftService;//内部接口 public CompletableFuture<Integer> getCancelTypeAsync(long orderId) { CompletableFuture<WmOrderOpRemarkResult> remarkResultFuture = wmOrderAdditionInfoThriftService.findOrderCancelledRemarkByOrderIdAsync(orderId);//业务方法,内部会发起异步rpc调用 return remarkResultFuture .exceptionally(err -> {//通过exceptionally 捕获异常,打印日志并返回默认值 log.error("WmOrderRemarkService.getCancelTypeAsync Exception orderId={}", orderId, err); return 0; }); }
runAsync()和supplyAsync()方法的本质区别就是获取的CompletableFuture对象是否带有计算结果(类似于Runnable接口和Callable接口的区别)。
带有Executor参数的方法用于传入指定的线程池执行器来进行多线程管理;
而未带有Executor参数的方法会使用默认的ForkJoinPool.commonPool()作为它的线程池进行多线程管理。
supplyAsync使用默认的ForkJoinPool来执行
其他的方法定义类似
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)