核心线程数(corePoolSize)是线程池长期维持的最小线程数,是任务提交时调度逻辑的第一道门槛,决定稳态并发的底盘。

线程池不是“开箱即用”的黑盒,它的行为完全由七个参数协同决定。配置不当轻则资源浪费、响应延迟,重则服务雪崩、OOM崩溃。关键不在堆参数,而在理解每个参数如何影响任务流转路径。
核心线程数(corePoolSize):稳态并发的底盘
它代表线程池长期维持的最小线程数量,不是“建议值”,而是调度逻辑的第一道门槛。
- 任务提交时,只要当前线程数
- 核心线程默认永不回收,长期驻留内存;若需释放,必须显式调用 allowCoreThreadTimeOut(true) 并配合 keepAliveTime。
- CPU 密集型任务(如图像压缩、加解密)建议设为 CPU 核心数 + 1,减少上下文切换损耗。
- IO 密集型任务(如数据库查询、HTTP 调用)建议设为 CPU 核心数 × 2 或按阻塞系数估算(例如阻塞占比 80%,可用公式:CPU 核数 / (1 − 0.8) = 5×核数)。
最大线程数(maximumPoolSize)与任务队列(workQueue):伸缩边界的联动开关
这两个参数必须一起看——maximumPoolSize 是否生效,完全取决于 workQueue 是否已满。
- 使用 LinkedBlockingQueue(无界队列):队列几乎不会满,线程池永远扩不到 maximumPoolSize,实际退化为固定大小线程池,风险是任务堆积导致内存溢出。
- 使用 ArrayBlockingQueue(有界队列):容量需结合单任务平均内存占用与峰值 QPS 估算,例如每任务占 1MB,允许最多堆积 1000 个,则设容量为 1000,此时 maximumPoolSize 才真正起作用。
- 使用 SynchronousQueue(直接交接队列):不存任务,提交即尝试交由空闲线程处理;失败则触发扩容逻辑,适合高吞吐、低延迟场景,但要求 maximumPoolSize 设置合理,否则极易触发拒绝。
- maximumPoolSize 建议设为 corePoolSize 的 2–4 倍,避免盲目设为 Integer.MAX_VALUE —— 线程本身消耗栈空间(默认 1MB/线程),过多线程会迅速耗尽 JVM 内存或系统文件句柄。
空闲存活时间(keepAliveTime + unit):非核心线程的“解聘期限”
该参数只约束超出 corePoolSize 的那部分线程(即临时工),控制洪峰过后线程池收缩速度。
- 单位必须明确指定,如 TimeUnit.SECONDS 或 TimeUnit.MILLISECONDS,避免隐式转换错误。
- IO 密集型服务可设为 30–60 秒,容忍短时流量波动;CPU 密集型服务建议 10–20 秒,快速释放计算资源。
- 若开启 allowCoreThreadTimeOut(true),核心线程也受此时间约束,适用于资源极度敏感或长周期低负载场景(如批处理后台服务)。
拒绝策略(RejectedExecutionHandler):最后防线的业务语义
只有当 workQueue 已满 且 当前线程数已达 maximumPoolSize 时,才会触发。选型本质是权衡业务容错性与系统稳定性。
- AbortPolicy(默认):抛出 RejectedExecutionException,适合强一致性场景(如支付扣款),让上游明确感知失败并重试或降级。
- CallerRunsPolicy:由提交任务的线程(如 Tomcat 的 worker 线程)同步执行该任务,能自然减缓提交速率,适合突发流量可控、且不允许丢任务的场景。
- DiscardPolicy:静默丢弃,适合日志采集、埋点上报等可丢失、非关键任务。
- DiscardOldestPolicy:丢弃队列头部最老任务,为新任务腾位置,适合任务有时间敏感性(如实时行情推送),但需注意可能丢掉关键中间状态。
不复杂但容易忽略

















