线程池配置关键在于理解参数间的调度逻辑与业务匹配:按CPU/IO密集型设定core/max线程数,选用ArrayBlockingQueue等有界队列防OOM,拒绝策略需结合业务兜底能力选择。

掌握线程池核心参数配置,关键不是背参数名,而是理解每个参数在系统资源调度中的实际作用。它本质上是给你的应用装上“流量节流阀”和“人力调度室”,得知道什么时候该留人、什么时候该排队、什么时候该拒客。
先搞懂线程池的执行逻辑链
任务提交后,线程池按固定顺序处理:
- 如果当前线程数 corePoolSize,直接创建新核心线程执行任务;
- 否则尝试把任务加进 workQueue;
- 队列满了,且当前线程数 maximumPoolSize,就创建非核心线程;
- 线程数已达 maximumPoolSize 且队列已满,触发 拒绝策略。
这个流程决定了:参数之间不是孤立的,而是环环相扣的依赖关系。比如你把队列设成无界,maximumPoolSize 就基本失效;把 corePoolSize 设得太小,大量任务会立刻挤进队列,可能撑爆内存。
按业务类型配线程数
别套公式,先看任务在干什么:
立即学习“Java免费学习笔记(深入)”;
- CPU 密集型(如图像压缩、加密计算):线程太多反而加剧上下文切换。推荐 corePoolSize = CPU 核数 + 1,maximumPoolSize 可设为相同值,避免伸缩开销;
- IO 密集型(如查数据库、调 HTTP 接口):线程常在等响应,可适当放大。常见配法是 corePoolSize = CPU 核数 × 2~4,maximumPoolSize 是 core 的 1.5 倍左右;
- 混合型:没有银弹。上线后用监控工具(如 Micrometer + Prometheus)观察线程活跃率、队列积压量、拒绝数,再反推调整。
队列选型不能只看“有界/无界”
队列不是缓冲区,它是你的第一道限流防线:
- ArrayBlockingQueue(有界):明确容量,能防止 OOM,适合对资源敏感的场景,但需预估峰值任务量;
- SynchronousQueue(不存任务):任务必须立刻被线程拿走,否则直接触发拒绝策略。适合高吞吐、低延迟、任务执行快的场景;
- LinkedBlockingQueue(默认无界):危险!看似省心,实则把压力全转给堆内存,容易因积压导致 Full GC 或 OOM;
- 慎用 PriorityBlockingQueue:优先级逻辑增加复杂度,且低优先级任务可能长期饿死。
拒绝策略要和业务兜底能力匹配
拒绝不是失败,是主动降级的信号:
- AbortPolicy(默认):抛异常。适合强一致、不允许丢任务的场景,但必须在调用方捕获并处理;
- CallerRunsPolicy:让提交任务的线程自己执行。能自然减缓生产者速度,适合下游不可控、需要自我保护的场景;
- DiscardPolicy:静默丢弃。适合日志上报、埋点等允许丢失的异步操作;
- DiscardOldestPolicy:丢最老任务,腾位置给新任务。适合实时性要求高的消息类场景。
选哪个,取决于你能不能接受丢任务、有没有降级路径、是否愿意让主线程阻塞。


















