MST

星途 面试题库

面试题:Java中CompletableFuture异步任务结果传递:多任务并行及结果合并策略

假设有多个CompletableFuture任务并行执行,每个任务返回一个整数列表中的元素处理后的结果(例如对列表中的每个数进行不同的运算)。所有任务完成后,需要将这些结果合并为一个总的结果(比如求所有结果的和)。如果其中某个任务执行失败,整个合并操作需要能够正确处理失败情况,返回一个特殊的错误标识。请设计并实现这个功能,详细阐述你所采用的并行策略、结果合并方法以及异常处理方式,同时说明为什么选择这样的实现方式。
17.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

并行策略

使用 CompletableFutureallOf 方法来并行执行多个任务。allOf 方法会等待所有给定的 CompletableFuture 都完成,这样可以充分利用多核 CPU 的优势,提高执行效率。

结果合并方法

使用 thenApply 方法在所有任务完成后对结果进行合并。可以通过遍历每个 CompletableFuture 的结果列表,然后将所有结果累加起来得到总的结果。

异常处理方式

为每个 CompletableFuture 设置 exceptionally 方法来处理单个任务的异常。如果任何一个任务抛出异常,exceptionally 方法会捕获异常并返回一个特殊的错误标识。同时,在合并结果时检查是否有任务返回了错误标识,如果有则直接返回错误标识,而不进行结果合并。

代码实现

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

public class CompletableFutureExample {

    // 模拟任务执行方法
    private static CompletableFuture<Integer> processElement(int num) {
        return CompletableFuture.supplyAsync(() -> {
            // 模拟一些处理,这里简单返回 num * 2
            return num * 2;
        });
    }

    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5);
        List<CompletableFuture<Integer>> futures = new ArrayList<>();

        // 创建并启动所有任务
        for (int num : numbers) {
            futures.add(processElement(num)
                  .exceptionally(ex -> {
                       // 处理单个任务的异常
                       System.out.println("Task failed: " + ex.getMessage());
                       return -1; // 特殊错误标识
                   }));
        }

        // 等待所有任务完成并合并结果
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        CompletableFuture<Integer> resultFuture = allFutures.thenApply(v -> {
            int total = 0;
            boolean hasError = false;
            for (CompletableFuture<Integer> future : futures) {
                try {
                    int result = future.get();
                    if (result == -1) {
                        hasError = true;
                        break;
                    }
                    total += result;
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
            return hasError? -1 : total;
        });

        // 获取最终结果
        try {
            int result = resultFuture.get();
            if (result == -1) {
                System.out.println("Overall operation failed");
            } else {
                System.out.println("Total result: " + result);
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

选择这样实现的原因

  1. 并行策略allOf 方法简单高效,能够方便地管理多个并行任务,并且等待所有任务完成,适合这种需要所有任务结果进行后续操作的场景。
  2. 结果合并方法thenApply 方法在所有任务完成后进行操作,符合需求。通过遍历结果列表进行累加,逻辑清晰易懂。
  3. 异常处理方式:为每个任务设置 exceptionally 方法可以确保单个任务失败不会影响其他任务的执行,并且能够及时捕获并处理异常。在合并结果时检查错误标识,保证整个合并操作能够正确处理失败情况。