MST

星途 面试题库

面试题:Java CompletableFuture结合线程池处理复杂异步流程

假设有一个业务场景,需要依次执行三个异步任务A、B、C,其中任务B依赖任务A的结果,任务C依赖任务B的结果。同时,使用自定义线程池来执行这些任务以提高效率。请用Java代码实现这个过程,并且在任务执行出错时进行适当的异常处理,确保整个流程的健壮性。
11.7万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
import java.util.concurrent.*;

public class AsyncTaskSequence {
    private static final int CORE_POOL_SIZE = 3;
    private static final int MAX_POOL_SIZE = 5;
    private static final long KEEP_ALIVE_TIME = 10L;
    private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;
    private static final int QUEUE_CAPACITY = 10;

    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TIME_UNIT,
                new ArrayBlockingQueue<>(QUEUE_CAPACITY));

        CompletableFuture.supplyAsync(() -> {
            try {
                return taskA();
            } catch (Exception e) {
                throw new CompletionException(e);
            }
        }, executor)
       .thenApplyAsync(resultA -> {
            try {
                return taskB(resultA);
            } catch (Exception e) {
                throw new CompletionException(e);
            }
        }, executor)
       .thenApplyAsync(resultB -> {
            try {
                return taskC(resultB);
            } catch (Exception e) {
                throw new CompletionException(e);
            }
        }, executor)
       .exceptionally(ex -> {
            System.out.println("任务执行出错: " + ex.getMessage());
            return null;
        })
       .thenRun(() -> executor.shutdown());
    }

    private static String taskA() throws Exception {
        // 模拟任务A执行
        System.out.println("任务A开始执行");
        TimeUnit.SECONDS.sleep(2);
        System.out.println("任务A执行完成");
        return "任务A的结果";
    }

    private static String taskB(String resultA) throws Exception {
        // 模拟任务B执行,依赖任务A的结果
        System.out.println("任务B开始执行,依赖任务A的结果: " + resultA);
        TimeUnit.SECONDS.sleep(2);
        System.out.println("任务B执行完成");
        return "任务B的结果";
    }

    private static String taskC(String resultB) throws Exception {
        // 模拟任务C执行,依赖任务B的结果
        System.out.println("任务C开始执行,依赖任务B的结果: " + resultB);
        TimeUnit.SECONDS.sleep(2);
        System.out.println("任务C执行完成");
        return "任务C的结果";
    }
}
  1. 线程池设置
    • 使用ThreadPoolExecutor创建一个自定义线程池,设置核心线程数为3,最大线程数为5,线程存活时间为10秒,任务队列容量为10。
  2. 任务执行
    • 使用CompletableFuture.supplyAsync方法在自定义线程池中执行任务A。如果任务A执行出错,将异常包装为CompletionException抛出。
    • 使用thenApplyAsync方法依赖任务A的结果执行任务B,同样如果任务B执行出错,将异常包装为CompletionException抛出。
    • 使用thenApplyAsync方法依赖任务B的结果执行任务C,若任务C执行出错,也将异常包装为CompletionException抛出。
  3. 异常处理
    • 使用exceptionally方法捕获整个任务链中出现的异常,并打印错误信息。
  4. 线程池关闭
    • 使用thenRun方法在任务链执行完成后关闭线程池。

这样可以确保在异步任务按顺序执行的同时,通过自定义线程池提高效率,并在任务执行出错时进行适当的异常处理,保证整个流程的健壮性。