集合与并发 整理
线程池七个参数,放进一次任务提交里看
理解核心线程、队列、最大线程与拒绝策略之间的先后关系。
先回答:提交任务后,线程池会先扩线程,还是先排队?
在正常运行状态下,工作线程少于核心线程数时,通常先尝试创建线程;达到核心线程数后,先尝试进入队列;入队失败时,再尝试在最大线程数以内增加线程;仍无法接纳时执行拒绝策略。关闭状态与并发状态变化还会影响接纳结果。
七个参数分别管什么
- corePoolSize:核心线程数量,是正常接纳流程中的重要分界。
- maximumPoolSize:允许创建的最大工作线程数量。
- keepAliveTime 与 unit:空闲线程的存活时长和时间单位。默认主要影响超过核心数量的线程,也可以允许核心线程超时。
- workQueue:等待执行的任务队列,容量与队列实现直接影响线程扩展及排队行为。
- threadFactory:创建线程,可设置清晰的名字、异常处理等。
- handler:任务无法被线程池接纳时执行的拒绝处理器。
用一个有界队列的例子理解
ThreadPoolExecutor pool = new ThreadPoolExecutor(
2, 4, 30, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(20),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
这里用小数字说明参数关系,不是通用生产配置。如果前面的任务一直没有完成,线程数达到 2 后,新任务会优先入队;队列满后才尝试扩展到最多 4 个线程。
实际并发执行中,任务完成和队列消费会同时发生,不能只按“第几个任务”机械判断最终线程数。
面试里容易漏掉的两点
- 使用可持续接纳任务的无界队列时,最大线程数通常不会像想象中那样发挥扩容作用,积压可能先吃掉内存。
- CallerRunsPolicy 会把压力转移到提交线程;提交线程如果是请求线程,就会增加请求延迟。线程池已关闭时,它不会按正常运行时的方式执行任务。
- 拒绝策略要与业务错误处理配合。不能不加判断地丢弃用户交易或余额相关任务。
参数该怎么定
先看 CPU 或 IO 特征、下游连接数量、任务耗时及可接受排队时间,再通过压测观察。公式只能作为起点,还应监控队列长度、拒绝次数、活跃线程和尾延迟。
延伸阅读
以上为个人整理。涉及版本实现和线上使用时,请结合对应文档与实际测试判断。