十九、异步任务编排CompletableFuture

本文介绍JDK 1.8+提供的CompletableFuture类,用于简化并发编程中异步任务的依赖控制。通过supplyAsync和thenCombineAsync等方法,可以轻松实现线程间依赖的异步任务编排。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、简介

并发编程中我们经常创建异步线程来执行任务。但是,当异步任务之间存在依赖关系时,使得我们开发过程变得更加复杂。比如:

1、线程2依赖于线程1的执行结果

2、线程3依赖于线程1和线程2执行结果的合并

要实现以上两个异步线程的依赖,我们可能会采用等待/通知、消费队列或者一些比较麻烦的逻辑来控制异步任务的的关系。这期间,你可能不得不考虑中间结果,以及并发临界点等问题。

总而言之,对于复杂的异步任务的控制不是一个容易的事情。

CompletableFuture 

completableFuture是JDK于1.8+提供的一个实现类,它主要用于异步任务的编排,很好地帮我们解决异步任务控制逻辑。

它实现了Future接口和CompletableStage接口,所以你可以像使用Future一样简单地使用CompletableFuture。

JDK文档:https://blog.fondme.cn/apidoc/jdk-1.8-google/java/util/concurrent/CompletableFuture.html

二、使用示例

线程2依赖于线程1的执行结果

// 线程1执行结果
CompletableFuture.supplyAsync(() -> "hello ")
                 // 消费线程1执行结果
                 .thenAccept(x -> System.out.println(x + "world"));

输出结果:

hello world

线程3依赖于线程1和线程2执行结果的合并

// 线程1执行结果
CompletableFuture.supplyAsync(() -> "hello ")
                 // 结合线程2执行结果
                 .thenCombineAsync(CompletableFuture.supplyAsync(() -> "world"), (x, y) -> x + y)
                 // 消费线程1和2的合并结果
                 .thenAccept(x -> System.out.println(x));

输出结果:

hello world

异步任务的编排,实际上是对同步和异步的交点进行了控制,Completable把这个控制逻辑从业务任务代码中抽离了出来。这样你可以更加专注于编写异步任务中的代码。

 

转载于:https://www.cnblogs.com/lay2017/p/10186386.html

### CompletableFuture 异步编排使用示例 #### 基本概念 `CompletableFuture` 是 Java 8 中引入的一个,用于支持异步编程模型。它提供了丰富的 API 来处理异步任务的结果以及多个异步任务之间的协作。 --- #### 示例代码展示 以下是几个典型的 `CompletableFuture` 异步编排的例子: ##### 1. 单一任务异步执行并获取结果 通过 `supplyAsync` 方法可以创建一个带有返回值的任务,并可以通过 `.get()` 获取最终结果[^1]。 ```java public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(10); CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getName()); return 10 / 2; }, executor); Integer result = future.get(); System.out.println("计算结果为: " + result); } ``` 上述代码展示了如何在一个固定大小的线程池中运行异步任务,并等待其完成以获得结果。 --- ##### 2. 链式调用与结果转换 通过链式调用的方式可以在前一个任务完成后继续操作其结果[^3]。 ```java public static void main(String[] args) throws Exception { CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "Hello"); CompletableFuture<Void> cf2 = cf1.thenAccept(result -> { System.out.println("接收到上游数据: " + result.toUpperCase()); }); cf2.get(); // 等待整个链条完成 } ``` 此例子说明了如何将第一个任务的结果传递给后续的操作函数,并对其进行进一步处理。 --- ##### 3. 组合两个独立任务的结果 当需要组合来自不同任务的数据时,可使用 `thenCombineAsync` 或其他似的组合方法[^2]。 ```java public static void main(String[] args) { String finalResult = CompletableFuture.supplyAsync(() -> "Java").thenCombine( CompletableFuture.supplyAsync(() -> " CompletableFuture"), (result1, result2) -> result1 + " and " + result2 ).join(); System.out.println(finalResult); // 输出:Java and CompletableFuture } ``` 这里演示了如何将两个并发执行的任务结果合并成一个新的字符串。 --- ##### 4. 执行动作而无需关心返回值 如果只需要触发某些副作用(side effect),而不关注具体返回值,则可以选择不带泛型参数的方法如 `runAsync` 和 `thenAccept`[^4]。 ```java public static void main(String[] args) { CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { try { Thread.sleep(2000L); } catch (InterruptedException e) {} System.out.println("后台任务已完成!"); }); future.join(); // 主线程会阻塞直到子任务结束 } ``` 这段程序表明即使没有实际产出任何有用的信息也可以利用这些工具来安排工作流。 --- ##### 5. 并发执行多个任务取最快完成者 有时我们可能希望发起多项竞争性的请求只保留最先到达的那个响应,在这种情况下可以用到 `anyOf` 函数。 ```java List<CompletableFuture<String>> futures = Arrays.asList( CompletableFuture.supplyAsync(() -> delayAndReturn("A", 3)), CompletableFuture.supplyAsync(() -> delayAndReturn("B", 1)) ); CompletableFuture<Object> fastestFuture = CompletableFuture.anyOf(futures.toArray(new CompletableFuture[0])); fastestFuture.whenComplete((res, throwable) -> System.out.println("最快的未来是:" + res)); private static String delayAndReturn(String name,int seconds){ try{ TimeUnit.SECONDS.sleep(seconds); } catch(Exception ex){} return name+" finished after "+seconds+" second(s)"; } ``` 在这个场景下,“B”的模拟延迟较短所以会被优先打印出来作为胜出方。 --- ### 总结 以上就是关于 `CompletableFuture` 的一些常见用法介绍及其对应的实现样例。它们涵盖了从简单的单次运算到复杂的多阶段依赖关系管理等多个方面的需求满足方式。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值