
1) 【一句话结论】
线程池参数需结合任务特性(IO/CPU密集)与资源限制(CPU核数、内存),核心线程数按任务类型设置(IO密集=CPU核数,CPU密集=CPU核数*2),最大线程数=核心线程数+队列容量,队列大小根据任务速率与处理能力动态调整,通过监控队列长度、线程数等指标避免OOM或CPU过高。
2) 【原理/概念讲解】
线程池的核心作用是通过复用线程减少创建销毁开销,关键参数包括核心线程数、最大线程数、任务队列和拒绝策略,它们共同决定了线程池的资源占用和任务处理能力。
最大线程数 = 核心线程数 + 队列容量。当任务数超过核心线程数时,新任务进入队列;队列满后,若线程数小于最大值,则启动新线程处理;若等于最大值,则触发拒绝策略。ArrayBlockingQueue(有界队列):容量固定,任务数超过容量时阻塞提交任务,避免内存溢出(OOM);SynchronousQueue(无界队列):任务提交时直接创建新线程,若线程数已达最大值,则任务阻塞,可能导致线程数无限增长,OOM;PriorityBlockingQueue(优先级队列):按任务优先级排序,适用于需优先处理高优先级任务的场景。队列容量 = (λ - μ) / λ 计算理论容量;或根据经验法则,如“队列长度超过阈值(如10)时,增加队列容量或提升处理能力”。DiscardPolicy(丢弃任务);CallerRunsPolicy(由提交任务的线程执行任务)或自定义处理(如写入持久化存储);AbortPolicy(默认策略,抛出异常)。3) 【对比与适用场景】
| 线程池类型 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 固定线程池 | FixedThreadPool | 核心线程数=最大线程数=固定值,队列无界 | 需固定并发数的任务(如定时任务) | 队列无界可能导致线程数无限增长,OOM |
| 缓存线程池 | CachedThreadPool | 核心线程数=0,最大线程数=Integer.MAX_VALUE,队列无界 | 需快速处理短任务(如HTTP请求) | 短任务频繁提交会导致线程数激增,CPU过高 |
| 可缓存线程池 | CachedThreadPool(同上) | 核心线程数=0,最大线程数=Integer.MAX_VALUE,队列无界 | 短任务、快速响应场景 | 空闲线程超时时间短(默认60秒),资源浪费 |
| 有界线程池 | ThreadPoolExecutor(自定义) | 核心线程数+最大线程数+有界队列 | 需控制资源(CPU/内存)的场景(如消息处理) | 队列大小需根据任务速率与处理能力调整,避免延迟或OOM |
| 可缩容线程池 | ThreadPoolExecutor(结合动态调整) | 核心线程数+最大线程数+有界队列+动态调整机制 | 高并发、负载波动的场景(如电商秒杀) | 需监控指标动态调整参数,避免资源浪费 |
4) 【示例】
假设消息处理服务需处理大量IO密集任务(如异步消息消费),使用ThreadPoolExecutor配置线程池:
public void processMessages(List<Message> messages) {
// 创建线程池(IO密集任务,核心线程数=CPU核数)
ThreadPoolExecutor pool = new ThreadPoolExecutor(
8, // 核心线程数:8核CPU,IO密集任务,核心线程数=CPU核数
16, // 最大线程数:核心线程数(8)+队列容量(假设队列8)
60L, TimeUnit.SECONDS, // 空闲线程超时时间:空闲60秒后销毁
new ArrayBlockingQueue<>(8), // 队列:有界队列,避免内存溢出
Executors.defaultThreadFactory(), // 线程工厂:默认创建线程
new ThreadPoolExecutor.DiscardOldestPolicy() // 拒绝策略:队列满时丢弃旧任务
);
// 提交任务
for (Message msg : messages) {
pool.execute(() -> {
// 模拟IO密集任务:调用外部服务
processMessage(msg);
});
}
// 关闭线程池
pool.shutdown();
}
(注:若任务为CPU密集型,核心线程数调整为CPU核数*2,如16核CPU设为32)
5) 【面试口播版答案】
“线程池参数选择要结合任务特性和资源限制。对于消息处理这类IO密集任务,核心线程数一般设为CPU核心数(比如8核CPU设为8个核心线程),因为IO等待时线程会空闲,充分利用CPU;最大线程数等于核心线程数加上队列容量(比如队列有8个任务,核心8个,最大16个),这样队列满时还能启动8个线程处理。队列大小用有界队列(比如ArrayBlockingQueue),避免内存溢出,队列大小根据任务处理速率和延迟要求调整(比如通过压力测试,当队列长度超过10时,增加队列容量)。避免OOM的话,监控队列长度,如果队列持续增长,说明任务太多,可能需要增加队列或提升处理能力;避免CPU过高,核心线程数设为CPU核数,这样CPU忙时不会超负荷,空闲时线程空闲。拒绝策略选合适的,比如队列满时丢弃旧任务,防止资源耗尽。”
6) 【追问清单】
队列容量 = (λ - μ) / λ 计算,或根据压力测试数据调整(如当队列长度超过阈值时,增加队列容量)。7) 【常见坑/雷区】