CompletableFuture详解。

CompletableFuture主要特点

  1. 异步执行:可以用来表示一个异步计算的结果。
  2. 链式调用:支持通过方法链来构建复杂的异步操作流程。
  3. 组合与合并:可以将多个 CompletableFuture 的结果进行组合或合并。
  4. 错误处理:提供了一种方式来处理异步操作中的异常。
  5. 非阻塞:可以在不阻塞主线程的情况下处理结果或异常。

创建 CompletableFuture

  • 立即完成
    • completedFuture(T value):创建一个已经完成的 CompletableFuture。
  • 延迟完成
    • supplyAsync(Supplier supplier):异步运行一个 Supplier 并返回其结果。
    • runAsync(Runnable runnable):异步运行一个 Runnable 操作(无返回值)。
    • 构造函数 CompletableFuture():创建一个新的 CompletableFuture 实例,但不立即启动任何任务。

处理结果

  • 同步处理
    • thenApply(Function<T, U> fn):对结果应用函数转换(异步任务计算结果将会作为参数传入处理函数中)。
    • thenAccept(Consumer action):消费结果而不返回新的结果(异步任务计算结果将会作为参数传入处理函数中)。
    • thenRun(Runnable action):在结果完成后执行一个动作,不关心结果(就是一个回调)。
  • 异步处理
    • 上述每个同步处理方法都有对应的异步版本(如 thenApplyAsync),这些方法会使用不同的线程来执行提供的函数。

组合与合并

  • 组合两个 Future
    • thenCompose(Function<T, CompletableFuture> fn):用于将当前 Future 的结果作为输入传递给另一个 Future。
  • 合并多个 Future
    • allOf(CompletableFuture<?>... cfs):等待所有给定的 Future 完成。
    • anyOf(CompletableFuture<?>... cfs):当任意一个给定的 Future 完成时结束。

错误处理

  • 异常处理
    • exceptionally(Function<Throwable, T> fn):为异常情况提供一个回退逻辑。
    • handle(BiFunction<T, Throwable, U> fn):无论正常完成还是异常抛出都可处理。

异步执行

completedFuture()

Java 官方文档对 CompletableFuture.completedFuture 方法的介绍如下:

 

java

代码解读

复制代码

public static <U> CompletableFuture<U> completedFuture(U value)

官方文档描述

  • 功能:返回一个已经完成的 value,其结果是给定的值。
  • 参数:value - 已经完成的结果值。
  • 返回:一个已完成的 CompletableFuture,其结果为提供的值。

详细说明

  • 这个方法用于创建一个已经成功完成的 CompletableFuture 实例。这个实例的状态被设置为已成功完成,并且它的结果就是传递给该方法的 value 参数。
  • 一旦创建了这样的 CompletableFuture 实例,它就不能再改变状态或结果。任何试图通过 complete, completeExceptionally, 或其他类似方法来改变其状态的操作都会抛出 IllegalStateException。
  • 该方法通常用于将现有的值包装成 CompletableFuture,以便可以使用 CompletableFuture 的链式调用和组合特性。

示例

 

arduino

代码解读

复制代码

import java.util.concurrent.CompletableFuture; public class Example { public static void main(String[] args) { // 创建一个已经完成的 CompletableFuture String result = "Hello, World!"; CompletableFuture<String> future = CompletableFuture.completedFuture(result); // 输出结果 System.out.println(future.join()); // 输出: Hello, World! // 继续执行后续操作 future.thenAccept(s -> System.out.println("Processed: " + s.toUpperCase())); } }

在这个例子中,completedFuture 方法被用来立即创建一个已经完成的 CompletableFuture,其结果是字符串 "Hello, World!"。然后,我们可以通过 join() 方法获取结果,或者添加更多的处理步骤(如 thenAccept)来进一步处理结果。

应用场景

  • 当你有一个同步计算的结果,并希望将其转换为异步形式时。
  • 在单元测试中模拟已完成的异步操作。
  • 将现有数据封装进 CompletableFuture,以便与其他异步操作进行组合。
supplyAsync()/runAsync()

CompletableFuture通过静态方法supplyAsync()/runAsync()来创建异步任务。

 

csharp

代码解读

复制代码

public class CompletableFutureDemo { public static void main(String[] args) { CompletableFuture.supplyAsync(()->{ int a = 1+2; return a; }).thenAccept((result)-> System.out.println("supplyAsync1:"+result)); CompletableFuture.supplyAsync(()->{ int a = 3+4; return a; },new ThreadPoolExecutor(1, 1, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2))).thenAccept((result)-> System.out.println("supplyAsync2:"+result)); } }

supplyAsync()有两个重载方法一个是使用默认线程池(ForkJoinPool.commonPool())执行异步任务,另一个可以传入一个自定义的线程池来执行异步任务。

 

swift

代码解读

复制代码

// 带返回值异步请求,默认线程池 public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) // 带返回值的异步请求,可以自定义线程池 public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

supplyAsync()于runAsync()的区别在于一个有返回值而另一个没有。

 

java

代码解读

复制代码

// 不带返回值的异步请求,默认线程池 public static CompletableFuture<Void> runAsync(Runnable runnable) // 不带返回值的异步请求,可以自定义线程池 public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

处理结果

同步处理与异步处理

CompletableFutureg还提供了一系列的实例方法用来处理异步任务执行结果并且这些方法都支持链式调用。

 

less

代码解读

复制代码

public class CompletableFutureDemo { public static void main(String[] args) { CompletableFuture.supplyAsync(()->{ int a = 1+2; System.out.println("task1:"+Thread.currentThread().getId()); return a; }).thenAccept((result)-> System.out.println("task2:"+Thread.currentThread().getId())); CompletableFuture.supplyAsync(()->{ int a = 3+4; System.out.println("task3:"+Thread.currentThread().getId()); return a; }).thenAcceptAsync((result)-> System.out.println("task4:"+Thread.currentThread().getId())); } }

通过上面的的代码可以发现,异步和同步的区别就是,在处理异步计算结果时,是用的线程是否与执行异步任务的线程是同一个线程。如果对于异步任务计算结果的处理速度很快,并且并不希望它占用额外的资源,那么就可以使用thenApply()/thenAccpte(),如果异步任务计算结果的处理是一个耗时较长的过程,那么建议使用thenApplyAsync(0/thenAccpteAsync(),并且建议自定义线程池,因为如果同步处理的话就会长时间占用执行异步任务的线程,特别是在并发较高的场景下可能导致系统的吞吐量严重下降。

组合与合并

使用 thenCompose 组合两个 Future

thenCompose 方法允许你将当前 CompletableFuture 的结果传递给另一个 CompletableFuture。这在你需要基于前一个异步操作的结果来启动新的异步操作时非常有用。

 

java

代码解读

复制代码

import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class ThenComposeExample { public static void main(String[] args) { // 第一个 CompletableFuture CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); // 模拟耗时操作 } catch (InterruptedException e) { throw new IllegalStateException(e); } return "Hello"; }); // 使用 thenCompose 将第一个 Future 的结果作为输入传递给第二个 Future CompletableFuture<String> combinedFuture = future1.thenCompose(result -> CompletableFuture.supplyAsync(() -> { try { Thread.sleep(500); // 模拟耗时操作 } catch (InterruptedException e) { throw new IllegalStateException(e); } return result + " World!"; }) ); // 获取最终结果 try { String finalResult = combinedFuture.get(); // 阻塞直到完成 System.out.println("Final Result: " + finalResult); // 输出: Final Result: Hello World! } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }

在这个例子中,future1 完成后,其结果被传递给一个新的 CompletableFuture,该 CompletableFuture 在完成时返回 "Hello World!"。

使用 allOf 等待所有 Future 完成

allOf 方法用于等待一组 CompletableFuture 全部完成。它返回一个新的 CompletableFuture,当所有给定的 CompletableFuture 都完成时,这个新的 CompletableFuture 也会完成。

 

java

代码解读

复制代码

import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class AllOfExample { public static void main(String[] args) { // 创建多个 CompletableFuture CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); // 模拟耗时操作 } catch (InterruptedException e) { throw new IllegalStateException(e); } return "Hello"; }); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1500); // 模拟耗时操作 } catch (InterruptedException e) { throw new IllegalStateException(e); } return "World"; }); // 使用 allOf 等待所有 Future 完成 CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2); // 当所有 Future 完成后,获取它们的结果 allFutures.thenRun(() -> { try { System.out.println("Future 1: " + future1.get()); System.out.println("Future 2: " + future2.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }); // 阻塞主线程以保持 JVM 运行 try { allFutures.get(); // 阻塞直到所有 Future 完成 } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }

在这个例子中,allOf 方法等待 future1 和 future2 都完成,然后通过 thenRun 方法获取并打印它们的结果。

使用 anyOf 当任意一个 Future 完成时结束

anyOf 方法用于等待一组 CompletableFuture 中的任意一个完成。它返回一个新的 CompletableFuture,当任意一个给定的 CompletableFuture 完成时,这个新的 CompletableFuture 也会完成,并且它的结果就是那个最先完成的 CompletableFuture 的结果。

 

typescript

代码解读

复制代码

import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class AnyOfExample { public static void main(String[] args) { // 创建多个 CompletableFuture CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(2000); // 模拟耗时操作 } catch (InterruptedException e) { throw new IllegalStateException(e); } return "Hello"; }); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); // 模拟耗时操作 } catch (InterruptedException e) { throw new IllegalStateException(e); } return "World"; }); // 使用 anyOf 等待任意一个 Future 完成 CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2); // 当任意一个 Future 完成时,获取结果 anyFuture.thenAccept(result -> { System.out.println("First to complete: " + result); }); // 阻塞主线程以保持 JVM 运行 try { anyFuture.get(); // 阻塞直到任意一个 Future 完成 } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }

在这个例子中,anyOf 方法等待 future1 和 future2 中的任意一个完成,并打印出最先完成的那个 CompletableFuture 的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值