面试题答案
一键面试自定义线程池优化CompletableFuture的runAsync任务执行性能
- 代码示例:
import java.util.concurrent.*;
import java.util.concurrent.CompletableFuture;
public class CompletableFutureThreadPoolExample {
public static void main(String[] args) {
// 创建自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
10L, TimeUnit.SECONDS, // 线程存活时间
new ArrayBlockingQueue<>(20), // 队列容量
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
// 使用自定义线程池执行CompletableFuture的runAsync任务
for (int i = 0; i < 100; i++) {
CompletableFuture.runAsync(() -> {
// 模拟任务执行
System.out.println("Task " + Thread.currentThread().getName() + " is running.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, executor);
}
// 关闭线程池
executor.shutdown();
}
}
- 不同线程池参数设置对任务执行的影响:
- 核心线程数:核心线程数决定了线程池在没有额外任务时会保留的线程数量。如果核心线程数设置过小,在任务量较大时,线程池可能需要频繁创建新线程,增加线程创建开销。例如,将核心线程数设置为1,在有大量任务时,可能导致任务执行延迟较大。如果核心线程数设置过大,会占用过多系统资源,即使在任务量较少时也会维持较多线程,造成资源浪费。
- 最大线程数:最大线程数限制了线程池能够创建的最大线程数量。如果最大线程数设置过小,当任务量超过队列容量且核心线程数已满时,新任务可能无法及时执行,导致任务堆积。例如,最大线程数设置为2,而同时有10个任务需要执行,超过最大线程数的任务只能在队列中等待或根据拒绝策略处理。如果最大线程数设置过大,可能会导致系统资源耗尽,因为过多线程会竞争CPU、内存等资源。
- 队列容量:队列用于存放等待执行的任务。如果队列容量设置过小,当任务产生速度超过线程处理速度且核心线程数已满时,任务很快就会填满队列,进而触发创建新线程(直到达到最大线程数),如果最大线程数也满了,就会根据拒绝策略处理任务。例如,队列容量设置为5,而同时有20个任务,很快队列会满,线程池开始创建新线程。如果队列容量设置过大,可能会导致任务长时间在队列中等待,造成任务执行延迟,因为只有核心线程和新创建线程处理完任务后,才会从队列中取新任务,并且过多任务在队列中可能占用大量内存。
总结
合理设置线程池的核心线程数、最大线程数和队列容量对于优化大量异步任务的执行性能至关重要。需要根据任务的特性(如任务执行时间、任务产生频率等)以及系统资源情况进行调优。