
1) 【一句话结论】处理高并发请求时,需根据任务特性(如秒杀的短任务)动态配置线程池参数:核心线程数设为CPU核心数(保证CPU利用率),最大线程数设为核心数加缓冲(应对突发请求),空闲线程存活时间设为短时间(及时回收资源),通过队列策略(如秒杀用无界队列直接传递任务)平衡性能与资源。
2) 【原理/概念讲解】
核心线程数(corePoolSize):长期运行的线程,用于处理常规任务,保持就绪状态(类比工厂的固定工人,每天上班处理日常订单,避免频繁创建销毁)。
最大线程数(maximumPoolSize):处理突发任务时额外创建的线程数,是线程池的最大容量(类比临时工,需求大时临时雇佣,需求小时解雇)。
空闲线程存活时间(keepAliveTime):当线程数超过核心数时,空闲线程等待的时间,超过则回收(类比临时工的合同期,合同期到就解雇)。
队列(Queue):任务等待的队列,如无界队列(SynchronousQueue,直接传递任务,无等待)、有界队列(LinkedBlockingQueue,有限容量,避免内存溢出)(秒杀场景中,请求处理时间短,用无界队列避免积压)。
3) 【对比与适用场景】
| 参数 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
corePoolSize | 核心线程数 | 长期存在,处理常规任务 | 长任务(如后台计算)、秒杀(短任务但需持续处理) | 过小导致请求积压,过大浪费资源 |
maximumPoolSize | 最大线程数 | 突发任务时额外线程数 | 短任务(如秒杀)、高并发IO任务 | 过小导致拒绝任务,过大资源浪费 |
keepAliveTime | 空闲线程存活时间 | 超过核心数的线程等待时间 | 短任务(及时回收),长任务(保持) | 时间过短导致频繁创建销毁,过长资源浪费 |
| 队列类型 | 任务等待队列 | 无界(SynchronousQueue)、有界(LinkedBlockingQueue) | 秒杀(无界,直接传递)、后台任务(有界,避免内存溢出) | 无界队列可能导致内存溢出,有界需设置容量 |
4) 【示例】
秒杀场景的线程池配置(假设CPU核心数8):
// 创建线程池
ExecutorService secKillPool = new ThreadPoolExecutor(
8, // corePoolSize: CPU核心数,保证CPU利用率
16, // maximumPoolSize: 核心数*2(缓冲应对突发请求)
5, // keepAliveTime: 5秒,空闲线程超时回收
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), // 队列:无界,直接传递任务,避免积压
Executors.defaultThreadFactory()
);
// 使用示例
secKillPool.submit(() -> {
// 秒杀逻辑:检查库存、扣减、返回结果
System.out.println("处理秒杀请求");
});
解释:核心线程8个(CPU满载),最大16个(应对突发请求),空闲线程5秒后回收,队列用SynchronousQueue直接传递任务,避免积压。
5) 【面试口播版答案】
(约80秒)
“面试官您好,处理高并发请求时,线程池参数配置需根据任务特性平衡性能和资源。核心线程数(corePoolSize)设为CPU核心数(比如8核设为8),保证CPU持续利用;最大线程数(maximumPoolSize)设为核心数加缓冲(比如16),应对突发请求;空闲线程存活时间(keepAliveTime)设为短时间(如5秒),及时回收资源。秒杀场景中,请求处理时间短(秒级),用无界队列(SynchronousQueue)直接传递任务,避免积压。这样既保证CPU利用率,又不会因线程过多导致资源浪费,还能快速响应突发请求。”
6) 【追问清单】
AbortPolicy)如何选择?CallerRunsPolicy(让调用线程执行),避免拒绝任务。getPoolSize、getActiveCount、getQueueSize),结合日志或监控工具(如Prometheus)。corePoolSize、maximumPoolSize),但需考虑线程切换开销。SynchronousQueue?7) 【常见坑/雷区】
keepAliveTime设为30秒,但实际空闲时间只有5秒,线程未及时回收)。LinkedBlockingQueue)处理秒杀短任务,导致队列满后任务积压,内存溢出。