MST

星途 面试题库

面试题:Java异步事件处理中的线程池管理及异常处理

在Java异步事件处理中,当使用自定义线程池配合CompletableFuture进行异步任务执行时,如何合理配置线程池参数?如果异步任务执行过程中抛出异常,怎样在CompletableFuture中优雅地捕获并处理这些异常?
32.0万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

线程池参数配置

  1. 核心线程数:根据任务类型和系统资源确定。如果是I/O密集型任务,核心线程数可设置为 2 * CPU核心数;如果是CPU密集型任务,核心线程数可设置为 CPU核心数 + 1。例如:
int corePoolSize = Runtime.getRuntime().availableProcessors() + 1;
  1. 最大线程数:一般对于I/O密集型任务,最大线程数可以适当增大,比如 4 * CPU核心数;对于CPU密集型任务,最大线程数可与核心线程数相同或稍大。例如:
int maximumPoolSize = 2 * Runtime.getRuntime().availableProcessors();
  1. 线程存活时间:设置线程在没有任务时保持存活的时间,对于使用CachedThreadPool这种动态创建和销毁线程的场景较为重要,可设为 5L,单位 TimeUnit.SECONDS 等。例如:
long keepAliveTime = 5L;
TimeUnit unit = TimeUnit.SECONDS;
  1. 队列容量:根据任务到达速率和处理速率调整。如果任务到达速率稳定且处理速率能跟上,队列容量可设置适中,如 100。例如:
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);
  1. 线程工厂:可自定义线程工厂来设置线程名称等属性,方便调试。例如:
ThreadFactory threadFactory = Executors.defaultThreadFactory();
  1. 拒绝策略:根据业务需求选择,常见的有 AbortPolicy(默认,直接抛出异常)、CallerRunsPolicy(调用者线程执行任务)、DiscardPolicy(丢弃任务)、DiscardOldestPolicy(丢弃队列最老的任务)。例如:
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

然后创建线程池:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        unit,
        workQueue,
        threadFactory,
        handler);

异常捕获与处理

  1. 使用 exceptionally 方法
CompletableFuture.supplyAsync(() -> {
    // 异步任务,可能抛出异常
    if (Math.random() > 0.5) {
        throw new RuntimeException("模拟异常");
    }
    return "任务成功结果";
}, executor)
.exceptionally(ex -> {
    System.out.println("捕获到异常: " + ex.getMessage());
    return "默认值";
})
.thenAccept(System.out::println);
  1. 使用 whenComplete 方法
CompletableFuture.supplyAsync(() -> {
    // 异步任务,可能抛出异常
    if (Math.random() > 0.5) {
        throw new RuntimeException("模拟异常");
    }
    return "任务成功结果";
}, executor)
.whenComplete((result, ex) -> {
    if (ex != null) {
        System.out.println("捕获到异常: " + ex.getMessage());
    } else {
        System.out.println("任务结果: " + result);
    }
});
  1. 使用 handle 方法
CompletableFuture.supplyAsync(() -> {
    // 异步任务,可能抛出异常
    if (Math.random() > 0.5) {
        throw new RuntimeException("模拟异常");
    }
    return "任务成功结果";
}, executor)
.handle((result, ex) -> {
    if (ex != null) {
        System.out.println("捕获到异常: " + ex.getMessage());
        return "默认值";
    }
    return result;
})
.thenAccept(System.out::println);