MST

星途 面试题库

面试题:Java CompletableFuture链式调用复杂场景下的错误处理与恢复策略

在一个包含多个依赖异步任务的CompletableFuture链式调用中,其中一些任务可能会因为资源竞争等原因间歇性失败。请设计一个全面的错误处理与恢复策略,不仅要处理单个任务的异常,还要考虑任务之间的依赖关系,确保整个链式调用在面对失败时能够尽可能恢复并完成最终目标,同时要求代码具备良好的性能和可维护性。请详细描述策略思路并给出关键代码片段。
32.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

策略思路

  1. 单个任务异常处理:使用exceptionally方法捕获每个CompletableFuture任务中的异常,以便在任务失败时进行相应处理。
  2. 依赖关系处理:确保异常处理逻辑不会破坏任务之间的依赖关系。如果某个任务失败,后续依赖它的任务应根据失败情况进行相应调整。
  3. 恢复机制:对于间歇性失败的任务,可以引入重试机制。例如,使用CompletableFuturewhenComplete方法结合重试逻辑,在任务失败时进行重试。
  4. 性能与可维护性:为了保证性能,重试次数应有限制,避免无限循环。同时,将重试逻辑封装成独立的方法,提高代码的可维护性。

关键代码片段

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureErrorHandling {

    // 重试次数限制
    private static final int MAX_RETRIES = 3;

    // 执行异步任务,带重试机制
    private static CompletableFuture<String> performTaskWithRetry(int taskNumber) {
        return performTask(taskNumber)
               .whenComplete((result, ex) -> {
                    if (ex != null && taskNumber < MAX_RETRIES) {
                        performTaskWithRetry(taskNumber + 1)
                               .whenComplete((r, e) -> {
                                    if (e != null && taskNumber == MAX_RETRIES - 1) {
                                        System.err.println("Task failed after max retries: " + taskNumber);
                                    }
                                });
                    }
                });
    }

    // 模拟异步任务
    private static CompletableFuture<String> performTask(int taskNumber) {
        return CompletableFuture.supplyAsync(() -> {
            // 模拟资源竞争导致的间歇性失败
            if (Math.random() < 0.5) {
                throw new RuntimeException("Task " + taskNumber + " failed due to resource competition");
            }
            return "Task " + taskNumber + " completed successfully";
        });
    }

    public static void main(String[] args) {
        CompletableFuture<Void> chain = performTaskWithRetry(1)
               .thenApply(result -> {
                    System.out.println(result);
                    return result;
                })
               .thenCompose(result -> performTaskWithRetry(2))
               .thenApply(result -> {
                    System.out.println(result);
                    return result;
                })
               .thenCompose(result -> performTaskWithRetry(3))
               .thenApply(result -> {
                    System.out.println(result);
                    return result;
                })
               .exceptionally(ex -> {
                    System.err.println("Final chain failed: " + ex.getMessage());
                    return null;
                })
               .thenRun(() -> System.out.println("Chain completed"));

        try {
            chain.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

在上述代码中:

  1. performTask方法模拟了一个可能会间歇性失败的异步任务。
  2. performTaskWithRetry方法实现了重试机制,在任务失败时会根据重试次数进行重试。
  3. main方法展示了如何通过CompletableFuture的链式调用构建依赖关系,并在其中应用错误处理和恢复策略。exceptionally方法用于捕获整个链式调用中的最终异常,确保即使有任务失败,程序也能有相应的处理并继续执行后续逻辑。