7.26

avatar
作者
筋斗云
阅读量:0

CompletableFuture

1、supplyAsync、runAsync

在 Java 的 CompletableFuture 类中,supplyAsyncrunAsync 是两个用于异步执行任务的方法。它们的主要区别在于处理返回值的方式和适用场景。下面详细介绍这两个方法。

1. supplyAsync

  • 功能: supplyAsync 方法用于异步执行一个可以返回结果的任务。
  • 返回值: 它返回一个 CompletableFuture<T>,其中 T 是通过任务计算得到的结果。
使用场景

适用于需要计算并返回结果的任务。

示例代码
import java.util.concurrent.CompletableFuture;  public class SupplyAsyncExample {     public static void main(String[] args) {         CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {             // 模拟一些计算             try {                 Thread.sleep(2000);             } catch (InterruptedException e) {                 Thread.currentThread().interrupt();             }             return 42; // 返回计算结果         });          // 等待结果并打印         future.thenAccept(result -> {             System.out.println("计算结果: " + result);         });          // 主线程可以继续执行其他任务         System.out.println("主线程继续执行...");                  // 等待 CompletableFuture 完成         future.join(); // 这里会阻塞直到 future 完成     } } 

2. runAsync

  • 功能: runAsync 方法用于异步执行一个不需要返回结果的任务。
  • 返回值: 它返回一个 CompletableFuture<Void>,表示任务的完成状态。
使用场景

适用于只需执行某些操作而不需要计算返回值的任务,例如日志记录、发送通知等。

示例代码
import java.util.concurrent.CompletableFuture;  public class RunAsyncExample {     public static void main(String[] args) {         CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {             // 模拟一些操作             try {                 Thread.sleep(2000);             } catch (InterruptedException e) {                 Thread.currentThread().interrupt();             }             System.out.println("任务完成!");         });          // 主线程可以继续执行其他任务         System.out.println("主线程继续执行...");          // 等待 CompletableFuture 完成         future.join(); // 这里会阻塞直到 future 完成     } } 

主要区别

特性supplyAsyncrunAsync
返回值返回计算结果的 CompletableFuture<T>返回 CompletableFuture<Void>
用途适用于需要结果的计算任务适用于不需要结果的执行操作
示例计算和返回一个值仅执行某些操作(如打印、更新状态)

总结

  • 使用 supplyAsync 当你需要执行一个计算并希望得到结果时。
  • 使用 runAsync 当你只想执行一个操作而不需要返回值时。

这两个方法都可以使你的程序在多线程环境中更加高效和响应迅速,特别适合处理 I/O 密集型或计算密集型任务。通过合理使用这两个方法,可以显著提高应用程序的性能和可扩展性。

2、allOf、anyOf

allOf

CompletableFuture.allOf 是 Java 中 CompletableFuture 类的一个静态方法,它允许你组合多个 CompletableFuture 实例,并在所有这些实例都完成时进行某种操作。allOf 返回一个新的 CompletableFuture<Void>,一旦所有传入的 CompletableFuture 都完成(无论是成功还是失败),这个新的 CompletableFuture 就会完成。

anyOf

CompletableFuture.anyOf 方法用于组合多个 CompletableFuture 实例,直到其中一个完成(成功或失败)。它返回一个新的 CompletableFuture,一旦任一给定的 CompletableFuture 完成,这个新的 CompletableFuture 就会完成,并且可以处理已完成的结果。

3、get

在 Java 的 CompletableFuture 中,get 方法用于获取 CompletableFuture 的计算结果。如果 CompletableFuture 还没有完成,调用 get 方法会导致当前线程阻塞,直到计算完成或者失败。此外,get 方法还有一个重载版本,允许你在获取结果时指定超时时间。

使用 get 方法

  1. 基本用法
    • get():阻塞当前线程,直到计算完成并返回结果。
    • get(long timeout, TimeUnit unit):阻塞当前线程,直到计算完成、超时或者发生异常。

示例代码

下面是一个使用 CompletableFuture.allOfget 方法的示例,展示如何处理多个异步任务,并在超时情况下进行异常处理。

import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException;  public class AllOfWithTimeoutExample {     public static void main(String[] args) {         // 创建多个异步任务         CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {             sleep(2000); // 模拟长时间运行的任务             return "Result from Future 1";         });                  CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {             sleep(1000); // 模拟较短时间的任务             return "Result from Future 2";         });                  CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {             sleep(1500); // 模拟中等时间的任务             return "Result from Future 3";         });          // 使用 allOf 等待所有任务完成         CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2, future3);          try {             // 等待所有任务完成,设置超时时间为 3 秒             allOfFuture.get(3, TimeUnit.SECONDS); // 如果超时,将抛出 TimeoutException              // 获取每个 future 的结果             String result1 = future1.get();             String result2 = future2.get();             String result3 = future3.get();              // 输出结果             System.out.println("所有任务完成:");             System.out.println(result1);             System.out.println(result2);             System.out.println(result3);         } catch (TimeoutException e) {             System.out.println("操作超时,未能在规定时间内完成。");         } catch (InterruptedException e) {             Thread.currentThread().interrupt(); // 恢复中断状态             System.out.println("任务被中断。");         } catch (ExecutionException e) {             System.out.println("任务执行异常: " + e.getCause());         }     }      private static void sleep(long millis) {         try {             Thread.sleep(millis);         } catch (InterruptedException e) {             Thread.currentThread().interrupt(); // 恢复中断状态         }     } } 

4、thenApply、thenAccept、thenCompose

在 Java 的 CompletableFuture 类中,thenApplythenAcceptthenCompose 是用于处理异步计算结果的三个重要方法。它们允许你在 CompletableFuture 完成时定义后续操作,但它们的使用场景和返回类型各不相同。下面详细介绍这三个方法。

1. thenApply

  • 功能: thenApply 方法用于对 CompletableFuture 的结果进行转换,返回一个新的结果。
  • 返回值: 返回一个新的 CompletableFuture<U>,其中 U 是通过给定的函数处理后的结果。
使用场景

适用于需要对异步计算结果进行进一步处理并返回新结果的场景。

示例代码
import java.util.concurrent.CompletableFuture;  public class ThenApplyExample {     public static void main(String[] args) {         CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {             return 42; // 原始计算结果         });          CompletableFuture<String> transformedFuture = future.thenApply(result -> {             return "结果是: " + result; // 转换结果         });          // 打印转换后的结果         transformedFuture.thenAccept(System.out::println);     } } 

2. thenAccept

  • 功能: thenAccept 方法用于处理 CompletableFuture 的结果,但不返回任何结果。
  • 返回值: 返回一个新的 CompletableFuture<Void>,表示处理完成。
使用场景

适用于只关心异步计算结果但不需要返回新结果的场景。

示例代码
import java.util.concurrent.CompletableFuture;  public class ThenAcceptExample {     public static void main(String[] args) {         CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {             return 42; // 原始计算结果         });          future.thenAccept(result -> {             System.out.println("结果是: " + result); // 处理结果         });     } } 

3. thenCompose

  • 功能: thenCompose 方法用于将一个 CompletableFuture 的结果转换为另一个 CompletableFuture。它通常用于处理依赖于前一个 CompletableFuture 结果的异步操作。
  • 返回值: 返回一个新的 CompletableFuture<U>,其中 U 是通过给定的函数处理后的结果。
使用场景

适用于当后续操作返回 CompletableFuture 时,需要将这些操作串联在一起的场景。

示例代码
import java.util.concurrent.CompletableFuture;  public class ThenComposeExample {     public static void main(String[] args) {         CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {             return 42; // 原始计算结果         });          CompletableFuture<String> finalFuture = future.thenCompose(result -> {             return CompletableFuture.supplyAsync(() ->                  "结果是: " + result // 依赖于前一个结果的异步操作             );         });          // 打印最终结果         finalFuture.thenAccept(System.out::println);     } } 

主要区别

方法功能返回值类型使用场景
thenApply转换结果并返回新结果CompletableFuture<U>需要对结果进行处理并返回新结果的场景
thenAccept处理结果但不返回任何结果CompletableFuture<Void>只关心计算结果但不需要返回新结果的场景
thenCompose将一个异步操作的结果与另一个异步操作链接在一起CompletableFuture<U>当后续操作需要依赖于前一个操作的结果并返回 CompletableFuture 的场景

总结

  • 使用 thenApply 当你需要对异步计算的结果进行转换并返回新结果时。
  • 使用 thenAccept 当你只想处理结果而不需要返回值时。
  • 使用 thenCompose 当你需要将一个 CompletableFuture 的结果传递给另一个异步操作时。
  • thenApply 是用于将前一个任务的结果转换为另一个结果,适合用于处理结果,不启动新的异步计算。
  • thenCompose 是用于将前一个任务的结果传递给一个返回新的 CompletableFuture 的函数,适合用于在前一个任务完成后,启动新的异步计算。

这三个方法提供了丰富的组合能力,使得使用 CompletableFuture 进行异步编程变得更加简单和灵活。通过合理使用这些方法,可以构建复杂的异步处理流程。

5、ForkJoinPool

ForkJoinPool 是 Java 中用于并行处理任务的一个线程池,特别适合处理可拆分的任务(Fork-Join 任务)。它是 Java 并发包的一部分,提供了一个高效的任务执行框架,能够充分利用多核处理器的优势。ForkJoinPool 使用了工作窃取算法(Work Stealing),使得空闲的工作线程可以窃取任务,从而提高系统的整体性能。

主要特点

  1. 可拆分任务: ForkJoinPool 特别适合处理可以被拆分成多个子任务的任务。它将大任务拆分成小任务,这些小任务可以并行执行。

  2. 工作窃取算法: 在工作窃取模型中,每个线程维护一个双端队列(Deque),当任务执行完成后,线程会尝试从自己的队列中获取新的任务。如果队列为空,线程会尝试从其他线程的队列中窃取任务。

  3. 简单的 API: ForkJoinPool 提供了简单的 API,可以通过 ForkJoinTask 类及其子类(如 RecursiveTaskRecursiveAction)来创建可拆分的任务。

总结

ForkJoinPool 是 Java 并发编程中的一个强大工具,适用于需要并行处理的可拆分任务。它通过工作窃取算法提高了多核处理器的利用率,并提供了简单的 API,方便开发者实现任务的分治和并行执行。通过使用 ForkJoinPool,可以显著提高计算密集型任务的性能。

6、总结

CompletableFuture 是 Java 8 引入的一个强大的工具,用于支持异步编程和并行计算。它提供了一种简洁、灵活的方式来处理异步任务,支持对结果的组合、转换和异常处理。以下是 CompletableFuture 的一些重要特点和使用概述。

主要特点

  1. 异步计算:

    • CompletableFuture 允许你在后台线程中异步执行任务,避免了阻塞主线程,从而提高应用程序的响应性。
  2. 结果组合:

    • 你可以将多个 CompletableFuture 组合在一起,通过 thenCombineallOfanyOf 等方法来处理多个异步操作的结果。
  3. 链式调用:

    • CompletableFuture 支持链式调用,使得你可以将多个异步操作串联在一起,形成清晰的处理流程。常用的方法包括 thenApplythenAcceptthenCompose 等。
  4. 异常处理:

    • 提供了灵活的异常处理机制,可以使用 exceptionallyhandlewhenComplete 方法来处理任务执行中的异常。
  5. 支持回调:

    • 可以注册回调函数,在任务完成时被调用,无论是正常完成还是异常完成。
  6. 工作窃取:

    • 基于 ForkJoinPoolCompletableFuture 可以充分利用多核处理器,提高并发执行的效率。

常用方法

  • 创建任务:

    • supplyAsync(Supplier<U> supplier):异步执行并返回结果。
    • runAsync(Runnable runnable):异步执行不返回结果的任务。
  • 处理结果:

    • thenApply(Function<? super T,? extends U> fn):对结果进行转换,返回新的结果。
    • thenAccept(Consumer<? super T> action):处理结果但不返回。
    • thenCompose(Function<? super T,? extends CompletionStage<U>> fn):将结果转换为另一个 CompletableFuture
  • 组合多个任务:

    • allOf(CompletableFuture<?>... cfs):等待所有 CompletableFuture 完成。
    • anyOf(CompletableFuture<?>... cfs):等待任意一个 CompletableFuture 完成。
  • 异常处理:

    • exceptionally(Function<Throwable, ? extends T> fn):处理异常并提供默认值。
    • handle(BiFunction<? super T,Throwable,? extends U> fn):处理结果和异常。

示例代码

以下是一个简单的示例,展示了如何使用 CompletableFuture 来执行异步计算并处理结果:

import java.util.concurrent.CompletableFuture;  public class CompletableFutureExample {     public static void main(String[] args) {         CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {             return 42; // 异步计算         });          future.thenApply(result -> {             return "结果是: " + result; // 转换结果         }).thenAccept(System.out::println) // 打印结果           .exceptionally(ex -> {               System.out.println("发生异常: " + ex.getMessage());               return null;           });     } } 

总结

CompletableFuture 提供了一种强大而灵活的方式来处理异步编程,能够轻松地实现并发操作、结果组合和异常处理。它使得 Java 开发者能够更方便地编写非阻塞代码,提高应用程序的性能和响应性。在现代 Java 应用中,CompletableFuture 是处理异步操作的重要工具。通过合理使用 CompletableFuture,你可以构建复杂的异步处理流程,并提高代码的可读性和可维护性。

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!