CompletableFuture——异步编程艺术 [复制链接]
发表于 2026-2-8 21:18:54 | 显示全部楼层 |阅读模式
目次

1、CompletableFuture是什么?
2、CompletableFuture和Future、CompletionStage的关系?
3、CompletableFuture常用方法
3.1、 创建 CompletableFuture 实例
3.2、完成时触发thenApply、thenAccept、thenRun
3.3、组合多个 CompletableFuture
3.4、非常处理处罚
3.5、其他方法
4、利用CompletableFuture 实现做肉丝面小案例


1、CompletableFuture是什么?

CompletableFuture是Java 8中引入的一个异步编程工具类,用于举行非壅闭的异步编程。它是Future接口的扩展,提供了更机动、更强大的功能
CompletableFuture可以用于处理处罚异步操纵,比方网络哀求、数据库查询等。与传统的线程和回调方法相比,CompletableFuture提供了更轻便和方便的编程模子。
利用CompletableFuture的重要步调如下:
   

  • 创建一个CompletableFuture对象,可以通过CompletableFuture类的静态方法来创建,如CompletableFuture.supplyAsync()和CompletableFuture.runAsync()。
  • 调用CompletableFuture对象的方法来界说异步操纵的实验逻辑。可以利用thenApply()、thenAccept()和thenRun()等方法来对结果举行处理处罚,大概利用whenComplete()和handle()等方法来处理处罚非常环境。
  • 利用CompletableFuture对象的get()方法来获取异步操纵的结果,大概利用join()方法来等候异步操纵的完成。
CompletableFuture还提供了一些其他功能,如组合多个CompletableFuture对象、并行实验异步任务、处理处罚超时等。通过这些功能,可以更机动地处理处罚复杂的异步编程需求。
总之,CompletableFuture是一个功能强大的异步编程工具类,提供了轻便、方便和机动的编程模子,可以资助开辟者更好地处理处罚异步操纵。
2、CompletableFuture和Future、CompletionStage的关系?


CompletableFuture 是 Future 接口的一个实现类,而且也实现了 CompletionStage 接口。
Future 接口代表一个异步盘算的结果,可以通过 get() 方法来获取盘算结果。但是 Future 接口中的方法较为有限,只能判定盘算是否完成、取消盘算和获取盘算结果(壅闭等候大概超时等候)等操纵。
CompletableFuture 类提供了更多的操纵方法,可以更方便地处理处罚异步盘算的结果。我们可以对盘算结果实验一系列的操纵,好比转换、组合、非常处理处罚等。它还提供了一些便捷的静态方法,可以将同步方法转换为异步方法,而且可以指定线程池大概实验器来实验异步操纵。
CompletionStage 接口是 CompletableFuture 的父接口,它界说了一些组合操纵的方法,而且可以与 CompletableFuture 举行链式调用。CompletableFuture 实现了 CompletionStage 接口,以是 可以利用 CompletionStage 接口中的方法。
   综上所述,可以得出一下结论:
  (1)CompletableFuture 是对 Future 的增强,而且也是 CompletionStage 的实现类。
  (2)CompletableFuture 提供了更多的操纵方法和扩展功能,可以更机动地处理处罚异步盘算的结果。
  (3)CompletionStage 接口则提供了一些组合操纵的方法,可以方便地对异步盘算结果举行串行或并行处理处罚。
  3、CompletableFuture常用方法

3.1、 创建 CompletableFuture 实例

  1. static CompletableFuture<Void> completedFuture(U value)
  2. static CompletableFuture<Void> runAsync(Runnable runnable)
  3. static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
  4. static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
  5. static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
复制代码
(1)CompletableFuture.completedFuture 
方法用来创建一个已经完成的CompletableFuture对象。这个对象的结果是事先指定好的一个值大概非常。
这个方法有一个参数,可以是恣意的范例,表现这个CompletableFuture对象的结果。返回值是一个已经完成的CompletableFuture对象。
  1. CompletableFuture<Void> completedFuture = CompletableFuture.completedFuture(null);
复制代码
(2)runAsync
方法吸收一个Runnable参数,表现实验无返回值的异步任务。它返回一个CompletableFuture<Void>对象。
  1. CompletableFuture<Void> runAsyncFuture = CompletableFuture.runAsync(() -> System.out.println("Run async"));
复制代码
(3)supplyAsync
方法吸收一个Supplier<T>参数,表现实验有返回值的异步任务。它返回一个CompletableFuture<T>对象。
  1. CompletableFuture<String> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> "Supply async");
复制代码
  runAsync和supplyAsync都是CompletableFuture类的静态方法,用于实验异步任务。
  区别在于方法的参数和返回值范例差异。runAsync实验无返回值的异步任务,supplyAsync实验有返回值的异步任务,并将结果包装在CompletableFuture对象中返回。
  3.2、完成时触发thenApply、thenAccept、thenRun

  1. <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
  2. <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
  3. CompletableFuture<Void> thenAccept(Consumer<? super T> action)
  4. CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
  5. CompletableFuture<Void> thenRun(Runnable action)
  6. CompletableFuture<Void> thenRunAsync(Runnable action)
复制代码
(1)thenApply(Function<? super T,? extends U> fn)
这个方法在 CompletableFuture 完成后,将利用该 CompletableFuture 的结果作为输入,实验给定的 Function。这个 Function 担当一个范例为 T 的参数并返回一个范例为 U 的结果。返回一个新的 CompletableFuture<U>,它将在 Function 实验完毕后完成。
  1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello").thenApply(s -> s + " World");
  2. System.out.println(future.get());  //Hello World
复制代码
(2)thenApplyAsync(Function<? super T,? extends U> fn)
与 thenApply 类似,但 thenApplyAsync 会异步地实验给定的 Function。这意味着它将在一个新线程中实验 Function,而不是在完成原始 CompletableFuture 的同一个线程中。
(3)thenAccept(Consumer<? super T> action)
这个方法在 CompletableFuture 完成后,将利用该 CompletableFuture 的结果作为输入,实验给定的 Consumer。Consumer 担当一个范例为 T 的参数并实验一些操纵,但不会返回任何结果。返回一个新的 CompletableFuture<Void>。
  1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
  2.         CompletableFuture<Void> stringCompletableFuture = future.thenAccept(s -> System.out.println(s+" World"));//Hello World
复制代码
(4)thenAcceptAsync(Consumer<? super T> action)
与 thenAccept 类似,但 thenAcceptAsync 会异步地实验给定的 Function。这意味着它将在一个新线程中实验 Function。
(5)thenRun(Runnable action)
这个方法在 CompletableFuture 完成后实验给定的 Runnable。这个 Runnable 不担当任何参数,也不返回任何结果。返回一个新的 CompletableFuture<Void>。
  1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
  2. CompletableFuture<Void> futureRun = future.thenRun(() -> System.out.println("Action completed"));
复制代码
(6)thenRunAsync(Runnable action)
与 thenRun 类似,但 thenRunAsync 会异步地实验给定的 Runnable。这意味着它将在一个新线程中实验 Runnable。
   区别:
  

  • thenApply 与 thenApplyAsync 的区别在于实验 Function 的线程。thenApply 通常在完成原始 CompletableFuture 的同一个线程中实验,而 thenApplyAsync 总是在一个新线程中实验。
  • thenAccept 与 thenAcceptAsync,以及 thenRun 与 thenRunAsync 的区别同理。
  • thenApply、thenAccept 和 thenRun 是同步操纵,意味着它们在当火线程上实验,除非前一个阶段是异步完成的。
  • thenApplyAsync、thenAcceptAsync 和 thenRunAsync 是异步操纵,意味着它们会在差异的线程上实验,通常是 ForkJoinPool.commonPool() 中的线程,大概可以通过提供一个自界说的 Executor 来指定。
3.3、组合多个 CompletableFuture

  1. static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
  2. static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
复制代码
(1)allOf(CompletableFuture<?>... cfs)
该方法吸收一个 CompletableFuture 数组,并返回一个新的 CompletableFuture<Void> 对象。这个方法会等候全部的 CompletableFuture 对象都实验完成,然后返回一个新的 CompletableFuture,它会在全部的 CompletableFuture 对象都实验完成后完成。如果恣意一个 CompletableFuture 对象抛出非常,那么它会将非常通报给返回的 CompletableFuture 对象。
比方,假设有两个 CompletableFuture 对象 cf1 和 cf2,我们可以利用 allOf 方法等候它们都实验完成:
  1. CompletableFuture<Void> allFutures = CompletableFuture.allOf(cf1, cf2);
复制代码
(2)anyOf(CompletableFuture<?>... cfs)
该方法与 allOf 方法类似,但是它会等候恣意一个 CompletableFuture 对象实验完成,然后返回一个新的 CompletableFuture<Object> 对象。假云云中恣意一个 CompletableFuture 对象完成时有返回值,那么它将利用第一个完成的 CompletableFuture 的返回值作为返回值通报给返回的 CompletableFuture 对象。
  1. CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(cf1, cf2);
复制代码
  总结:
  这两个方法都黑白壅闭的,即它们会立刻返回一个 CompletableFuture 对象,不会等候 CompletableFuture 对象的实验完成。可以利用 thenApply、thenAccept 大概 thenRun 等方法来注册回调函数,以处理处罚 CompletableFuture 的结果。 
  3.4、非常处理处罚

  1. <U> CompletableFuture<U> exceptionally(Function<Throwable, ? extends U> fn)
  2. <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
复制代码
(1)CompletableFuture<U> exceptionally(Function<Throwable, ? extends U> fn)
该方法可以用来处理处罚非常环境。它担当一个Function参数,该参数是一个非常处理处罚函数,用于处理处罚出现的非常。如果CompletableFuture中发生了非常,那么这个非常会被通报给exceptionally方法,并由该方法的参数函数举行处理处罚。处理处罚完成后,exceptionally方法会返回一个新的CompletableFuture对象,该对象的结果是由非常处理处罚函数的返回值决定。如果原始的CompletableFuture没有发生非常(即正常完成),那么exceptionally方法会返回一个与原始CompletableFuture雷同的CompletableFuture对象。
(2)CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
该方法也可以用于处理处罚非常环境。它担当一个BiFunction参数,该参数是一个处理处罚函数,用于处理处罚正常结果或非常。如果CompletableFuture正常完成,那么handle方法会将结果和非常值作为参数通报给处理处罚函数。处理处罚函数的返回值将被用作新的CompletableFuture的结果。如果CompletableFuture发生非常,那么handle方法会将非常和null作为参数通报给处理处罚函数。处理处罚函数的返回值也将被用作新的CompletableFuture的结果。
  1. public class CompletableFutureDemo {
  2.     public static void main(String[] args) {
  3.         // 创建CompletableFuture
  4.         CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
  5.             // 模拟抛出异常
  6.             throw new RuntimeException("Exception occurred");
  7.         });
  8.         // 使用exceptionally处理异常
  9.         CompletableFuture<String> exceptionHandledFuture = future.exceptionally(ex -> {
  10.             return "Exception handled: " + ex.getMessage();
  11.         });
  12.         // 使用handle处理结果或异常
  13.         CompletableFuture<String> resultFuture = future.handle((res, ex) -> {
  14.             if (ex != null) {
  15.                 return "Exception handled: " + ex.getMessage();
  16.             } else {
  17.                 return res;
  18.             }
  19.         });
  20.         // 打印结果
  21.         System.out.println(exceptionHandledFuture.join());
  22.         System.out.println(resultFuture.join());
  23.     }
  24. }
复制代码
总结起来,exceptionally方法和handle方法都是用于处理处罚CompletableFuture发生的非常环境。它们提供了一种方式来处理处罚非常并返回一个新的CompletableFuture对象,使得我们可以大概在异步操纵完成后举行进一步的处理处罚。
3.5、其他方法

  1. <U> CompletableFuture<U> newIncompleteFuture()
  2. boolean complete(T value)
  3. boolean completeExceptionally(Throwable ex)
  4. T getNow(T valueIfAbsent)
  5. T join()
  6. boolean isDone()
  7. boolean isCancelled()
  8. boolean cancel(boolean mayInterruptIfRunning)
复制代码
(1)<U> CompletableFuture<U> newIncompleteFuture()
这个方法返回一个新的 CompletableFuture,它与当前实例具有雷同的特性(比方,异步实验的特性),但是没有完成的值或非常。通常用于创建自界说的 CompletableFuture 实现或扩展。
  1. CompletableFuture<String> future = new CompletableFuture<>();
  2. CompletableFuture<String> newFuture = future.newIncompleteFuture();
复制代码
(2)boolean complete(T value)
这个方法实验将给定的值设置为 CompletableFuture 的结果。如果 CompletableFuture 已经完成,则返回 false;否则,它会被设置为给定的值,并返回 true。
  1. CompletableFuture<String> future = new CompletableFuture<>();
  2. boolean completed = future.complete("Completed value");
  3. System.out.println("Future completed: " + completed); // 输出 true
复制代码
(3)boolean completeExceptionally(Throwable ex)
这个方法实验将给定的非常设置为 CompletableFuture 的非常结果。如果 CompletableFuture 已经完成,则返回 false;否则,它会被设置为给定的非常,并返回 true。
  1. CompletableFuture<String> future = new CompletableFuture<>();
  2. boolean completedExceptionally = future.completeExceptionally(new Exception("Error"));
  3. System.out.println("Future completed exceptionally: " + completedExceptionally); // 输出 true
复制代码
(4)T getNow(T valueIfAbsent)
这个方法返回 CompletableFuture 的当前值,如果没有完成,则返回给定的默认值 valueIfAbsent。
  1. CompletableFuture<String> future = CompletableFuture.completedFuture("Hello");
  2. String value = future.getNow("Default");
  3. System.out.println(value); // 输出 Hello
  4. CompletableFuture<String> futureNotCompleted = new CompletableFuture<>();
  5. String defaultValue = futureNotCompleted.getNow("Default");
  6. System.out.println(defaultValue); // 输出 Default
复制代码
(5)T join()
这个方法与 getNow 类似,但它会壅闭当火线程直到 CompletableFuture 完成,然后返回结果。如果 CompletableFuture 已经完成,它将立刻返回结果。
  1. CompletableFuture<String> future = CompletableFuture.completedFuture("Hello");
  2. String value = future.join();
  3. System.out.println(value); // 输出 Hello
复制代码
(6)boolean isDone()
这个方法返回 CompletableFuture 是否已经完成。完成大概是正常完成,也大概是由于非常。
  1. CompletableFuture<String> future = new CompletableFuture<>();
  2. System.out.println("Future is done: " + future.isDone()); // 输出 false
  3. future.complete("Completed");
  4. System.out.println("Future is done: " + future.isDone()); // 输出 true
复制代码
(7)boolean isCancelled()
这个方法返回 CompletableFuture 是否已经被取消。
  1. CompletableFuture<String> future = new CompletableFuture<>();
  2. System.out.println("Future is cancelled: " + future.isCancelled()); // 输出 false
  3. boolean cancelled = future.cancel(true);
  4. System.out.println("Future is cancelled: " + future.isCancelled()); // 输出 true
复制代码
(8)boolean cancel(boolean mayInterruptIfRunning)
这个方法实验取消 CompletableFuture 的实验。如果 CompletableFuture 已经完成,则返回 false。如果 mayInterruptIfRunning 为 true,而且 CompletableFuture 正在运行,那么它将被停止。
  1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
  2.     try {
  3.         Thread.sleep(1000);
  4.     } catch (InterruptedException e) {
  5.         Thread.currentThread().interrupt();
  6.     }
  7.     return "Result";
  8. });
  9. boolean cancelled = future.cancel(true);
  10. System.out.println("Future cancelled: " + cancelled); // 输出 true
复制代码
4、利用CompletableFuture 实现做肉丝面小案例

如今为了好明确并发编程的头脑,这里我准备了一个贴合现实的小案例,就是做一碗肉丝面,我们先梳理一下做面的步调过程,大抵是一下几个步调
1、备菜(切肉丝、切葱姜蒜、调味料、洗青菜、面条) (5分钟)

2、炒菜(下入肉丝、葱姜蒜翻炒、调味料调味) (2分钟)

3、煮开水 (10分钟)

4、下面条(煮3分钟)

5、下青菜再煮一会(1分钟)

6、完成
如果按照同步实验的话,就是代码依次从上往下实验,统共必要21分钟的时间,那么我们通过并发头脑来节省一下时间。我们思索一下,备菜和煮开水是不是可以一起实验,由于我可以两个一起实验,如许是不是就可以节省时间了。具体实现参考下面代码
  1. import java.util.concurrent.*;
  2. public class CompletableFutureDemo {
  3.     public static void main(String[] args) {
  4.         // 创建自定义线程池
  5.         int corePoolSize = 2; // 核心线程数
  6.         int maximumPoolSize = 4; // 最大线程数
  7.         long keepAliveTime = 60; // 非核心线程空闲存活时间
  8.         TimeUnit unit = TimeUnit.SECONDS; // 时间单位
  9.         BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); // 阻塞队列
  10.         ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂
  11.         RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy(); // 拒绝策略
  12.         ThreadPoolExecutor customThreadPool = new ThreadPoolExecutor(
  13.                 corePoolSize,
  14.                 maximumPoolSize,
  15.                 keepAliveTime,
  16.                 unit,
  17.                 workQueue,
  18.                 threadFactory,
  19.                 handler
  20.         );
  21.         // 步骤1:备菜
  22.         long startTime = System.currentTimeMillis();
  23.         CompletableFuture<Void> prepareIngredients = CompletableFuture.runAsync(() -> {
  24.             System.out.println("开始备菜...");
  25.             // 模拟切肉丝、切葱姜蒜、准备调味料、洗青菜、面条
  26.             try {
  27.                 TimeUnit.SECONDS.sleep(5);
  28.             } catch (InterruptedException e) {
  29.                 e.printStackTrace();
  30.             }
  31.             System.out.println("备菜完成。");
  32.         },customThreadPool);
  33.         // 步骤2:炒菜  使用thenRunAsync,等待步骤1执行结束再执行炒菜步骤
  34.         CompletableFuture<Void> stirFry = prepareIngredients.thenRunAsync(() -> {
  35.             System.out.println("开始炒菜...");
  36.             // 模拟下入肉丝、葱姜蒜翻炒、调味料调味
  37.             try {
  38.                 TimeUnit.SECONDS.sleep(2);
  39.             } catch (InterruptedException e) {
  40.                 e.printStackTrace();
  41.             }
  42.             System.out.println("炒菜完成。");
  43.         },customThreadPool);
  44.         // 步骤3:煮开水 可以直接使用runAsync,与步骤1备菜并行执行
  45.         CompletableFuture<Void> boilWater = CompletableFuture.runAsync(() -> {
  46.             System.out.println("开始煮开水...");
  47.             // 模拟煮开水的过程
  48.             try {
  49.                 TimeUnit.SECONDS.sleep(10);
  50.             } catch (InterruptedException e) {
  51.                 e.printStackTrace();
  52.             }
  53.             System.out.println("水开了。");
  54.         },customThreadPool);
  55.         // 步骤4:下面条  使用allOf  等待步骤2、步骤3执行结束再执行
  56.         CompletableFuture<Void> cookNoodles = CompletableFuture.allOf(stirFry, boilWater).thenRunAsync(() -> {
  57.             System.out.println("下面条...");
  58.             // 模拟煮面条的过程
  59.             try {
  60.                 TimeUnit.SECONDS.sleep(3);
  61.             } catch (InterruptedException e) {
  62.                 e.printStackTrace();
  63.             }
  64.             System.out.println("面条煮熟了。");
  65.         },customThreadPool);
  66.         // 步骤5:下青菜再煮   等待步骤4结束执行
  67.         CompletableFuture<Void> cookVegetables = cookNoodles.thenRunAsync(() -> {
  68.             System.out.println("下青菜...");
  69.             // 模拟下青菜的过程
  70.             try {
  71.                 TimeUnit.SECONDS.sleep(1);
  72.             } catch (InterruptedException e) {
  73.                 e.printStackTrace();
  74.             }
  75.             System.out.println("青菜煮熟了。");
  76.             System.out.println("完成烹饪,可以享用了!");
  77.         },customThreadPool);
  78.         // 等待所有步骤完成
  79.         try {
  80.             cookVegetables.get();
  81.         } catch (InterruptedException e) {
  82.             Thread.currentThread().interrupt();
  83.         } catch (ExecutionException e) {
  84.             throw new RuntimeException(e);
  85.         }finally {
  86.             // 关闭线程池
  87.             customThreadPool.shutdown();
  88.         }
  89.         long endTime = System.currentTimeMillis();
  90.         System.out.println("共消耗了:" + (endTime - startTime) / 1000 + "秒");
  91.     }
  92. }
复制代码

可以看到,通过异步实验,14分钟(贴合现实,换算为分钟)就完成了肉丝面的制作,节省了7分钟的时间,服从提升了33%。
感谢您的阅读,制作不易,喜欢这篇文章的小同伴们点赞关注支持一下吧。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表