MST

星途 面试题库

面试题:Java CompletableFuture在高并发场景下的资源管理与优化

在一个高并发的业务场景中,使用CompletableFuture执行大量异步任务。由于系统资源有限,例如线程池大小固定,如何合理配置CompletableFuture以避免资源耗尽,同时保证任务执行的高效性?请阐述具体的策略和可能用到的方法,并举例说明如何监控和调整相关资源参数。
31.7万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

策略

  1. 合理设置线程池
    • 分析任务类型(CPU 密集型、I/O 密集型等)。对于 CPU 密集型任务,线程池大小一般设置为 CPU 核心数 + 1;对于 I/O 密集型任务,线程池大小可适当增大,例如 CPU 核心数 * 2 或更多,以充分利用等待 I/O 的时间。
    • 使用 ThreadPoolExecutor 自定义线程池,设置合适的核心线程数、最大线程数、队列容量等参数。
  2. 任务队列管理
    • 选择合适的任务队列。如 LinkedBlockingQueue 可设置有界队列,防止任务无限堆积耗尽内存;SynchronousQueue 不存储任务,直接将任务交给线程处理,适用于任务处理速度快且需要快速响应的场景。
  3. 任务优先级
    • 对于关键业务任务,可设置较高优先级,优先从队列中取出执行。在自定义任务类中实现 Comparable 接口,重写 compareTo 方法来定义优先级规则,然后使用 PriorityQueue 作为任务队列。

方法

  1. 创建线程池
    ExecutorService executor = new ThreadPoolExecutor(
        10, // 核心线程数
        20, // 最大线程数
        10L, // 线程存活时间
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(100) // 队列容量
    );
    
  2. 使用 CompletableFuture 结合线程池执行任务
    CompletableFuture.supplyAsync(() -> {
        // 任务逻辑
        return result;
    }, executor);
    

监控和调整资源参数

  1. 监控
    • 使用 JMX(Java Management Extensions)ThreadPoolExecutor 本身支持 JMX,可以通过 JMX 监控线程池的运行状态,如活跃线程数、已完成任务数、队列大小等。
    • 自定义监控指标:在任务执行前后记录时间、任务数量等,例如:
    long startTime = System.currentTimeMillis();
    CompletableFuture.supplyAsync(() -> {
        // 任务逻辑
        return result;
    }, executor)
    

.thenApply(r -> { long endTime = System.currentTimeMillis(); System.out.println("Task took " + (endTime - startTime) + " ms"); return r; });

2. **调整**:
- 根据监控数据,如果队列经常满且任务响应时间长,可适当增加线程池大小或队列容量;如果活跃线程数长时间接近最大线程数且系统负载高,可能需要优化任务逻辑或降低任务提交频率。例如,通过动态修改 `ThreadPoolExecutor` 的核心线程数和最大线程数:
```java
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
executor.setCorePoolSize(15);
executor.setMaximumPoolSize(25);