MST

星途 面试题库

面试题:Java中CompletableFuture自定义线程池supplyAsync方法的异常处理

使用CompletableFuture的supplyAsync方法结合自定义线程池执行一个可能会抛出异常的异步任务,自定义线程池为ThreadPoolExecutor customExecutor。要求在任务出现异常时进行捕获处理,并将异常信息返回给调用者,同时阐述如何避免因线程池关闭导致任务无法执行的问题,写出完整代码并说明关键步骤。
33.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

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

public class CompletableFutureExample {

    // 自定义线程池
    private static final ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
            2,
            4,
            10L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10));

    public static void main(String[] args) {
        // 异步任务
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 模拟可能抛出异常的任务
            if (Math.random() < 0.5) {
                throw new RuntimeException("任务执行出错");
            }
            return "任务成功执行";
        }, customExecutor);

        // 处理异常并返回异常信息
        future.exceptionally(ex -> {
            System.out.println("捕获到异常: " + ex.getMessage());
            return "异常信息: " + ex.getMessage();
        }).thenAccept(System.out::println);

        // 避免因线程池关闭导致任务无法执行
        AtomicBoolean isShutdown = new AtomicBoolean(false);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            if (!isShutdown.getAndSet(true)) {
                customExecutor.shutdown();
                try {
                    if (!customExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
                        customExecutor.shutdownNow();
                        if (!customExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
                            System.err.println("Pool did not terminate");
                        }
                    }
                } catch (InterruptedException ie) {
                    customExecutor.shutdownNow();
                    Thread.currentThread().interrupt();
                }
            }
        }));
    }
}

关键步骤说明

  1. 创建自定义线程池:使用ThreadPoolExecutor创建了一个自定义线程池customExecutor,设置了核心线程数、最大线程数、线程存活时间以及任务队列。
  2. 执行异步任务:通过CompletableFuture.supplyAsync方法,将异步任务提交到自定义线程池customExecutor中执行。任务中模拟了可能抛出异常的情况。
  3. 异常处理:使用exceptionally方法捕获异步任务执行过程中抛出的异常,并返回包含异常信息的字符串。
  4. 避免线程池关闭问题:通过Runtime.getRuntime().addShutdownHook添加一个钩子函数,在程序关闭时,优雅地关闭线程池。先调用shutdown方法,尝试平稳关闭线程池,如果等待一段时间后仍未关闭,则调用shutdownNow方法强制关闭,并再次等待一段时间确保线程池完全关闭。同时使用AtomicBoolean来防止多次关闭线程池。