MST

星途 面试题库

面试题:Java异步编程中CompletableFuture的使用及原理

在Java异步编程场景下,如何使用CompletableFuture实现多个异步任务的链式调用、并行执行以及处理异常?并说明其内部的实现原理。
12.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

链式调用

在Java中,CompletableFuture可以通过thenApplythenAcceptthenRun等方法实现链式调用。

  1. thenApply: 用于对前一个CompletableFuture的结果进行转换,返回一个新的CompletableFuture
CompletableFuture.supplyAsync(() -> "Hello")
    .thenApply(s -> s + ", World")
    .thenApply(String::toUpperCase)
    .thenAccept(System.out::println);
  1. thenAccept: 用于对前一个CompletableFuture的结果进行消费,不返回新的结果。
CompletableFuture.supplyAsync(() -> "Hello")
    .thenAccept(s -> System.out.println(s + ", World"));
  1. thenRun: 在前一个CompletableFuture完成时执行一个无参数的任务。
CompletableFuture.supplyAsync(() -> "Hello")
    .thenRun(() -> System.out.println("Task completed"));

并行执行

CompletableFuture可以通过allOfanyOf方法实现多个异步任务的并行执行。

  1. allOf: 等待所有CompletableFuture都完成。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result2");

CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);
allFutures.thenRun(() -> {
    try {
        String result1 = future1.get();
        String result2 = future2.get();
        System.out.println(result1 + " " + result2);
    } catch (Exception e) {
        e.printStackTrace();
    }
}).join();
  1. anyOf: 只要有一个CompletableFuture完成,就返回。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Result1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result2");

CompletableFuture.anyOf(future1, future2)
    .thenApply(Object::toString)
    .thenAccept(System.out::println)
    .join();

处理异常

CompletableFuture提供了exceptionallyhandle等方法来处理异常。

  1. exceptionally: 当CompletableFuture发生异常时,返回一个默认值。
CompletableFuture.supplyAsync(() -> {
    if (Math.random() < 0.5) {
        throw new RuntimeException("Simulated exception");
    }
    return "Success";
})
.exceptionally(ex -> {
    System.out.println("Caught exception: " + ex.getMessage());
    return "Default value";
})
.thenAccept(System.out::println);
  1. handle: 可以同时处理正常结果和异常情况,返回一个新的结果。
CompletableFuture.supplyAsync(() -> {
    if (Math.random() < 0.5) {
        throw new RuntimeException("Simulated exception");
    }
    return "Success";
})
.handle((result, ex) -> {
    if (ex != null) {
        System.out.println("Caught exception: " + ex.getMessage());
        return "Default value";
    }
    return result;
})
.thenAccept(System.out::println);

内部实现原理

  1. 异步执行: CompletableFuture利用ForkJoinPool.commonPool()线程池来执行异步任务,通过AsynchronousCompletionTask接口实现任务的异步执行。
  2. 链式调用: 通过在CompletableFuture对象上注册回调函数实现链式调用。当一个CompletableFuture完成时,会触发注册的回调函数,回调函数可以对结果进行处理并返回新的CompletableFuture
  3. 并行执行: allOf方法通过创建一个新的CompletableFuture,并等待所有传入的CompletableFuture都完成,anyOf方法则是只要有一个CompletableFuture完成就返回。
  4. 异常处理: CompletableFuture内部通过tryCompleteThrowable方法来设置异常,当设置异常后,会触发注册的异常处理回调函数,如exceptionallyhandle中注册的回调。