逐行、深入地详解 ThreadPoolExecutor 的这个构造方法
,帮助你真正理解线程池的核心参数和工作原理。
🧱 构造方法签名
java深色版本public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
这是 ThreadPoolExecutor
最常用的一个构造函数,它使用了默认的线程工厂(defaultThreadFactory
)和默认拒绝策略(AbortPolicy
),简化了创建过程。
底层其实是调用了完整版的构造器:
java深色版本this(corePoolSize, ..., workQueue, Executors.defaultThreadFactory(), defaultHandler);
✅ 五个核心参数详解
1. corePoolSize
:核心线程数
- 含义:线程池中长期保留的线程数量,即使它们是空闲的(idle)。
- 行为:
💡 类比:公司里的正式员工,哪怕没活干也留着。
2. maximumPoolSize
:最大线程数
- 含义:线程池允许存在的最大线程总数(包括核心线程 + 临时线程)。
- 限制:
⚠️ 必须满足:maximumPoolSize >= corePoolSize,否则抛出 IllegalArgumentException。
3. keepAliveTime
+ unit
:非核心线程的存活时间
- 含义:当线程池中的线程数 >
corePoolSize
时,多余的空闲线程等待新任务的最长时间。 - 单位:由
TimeUnit
指定,如TimeUnit.SECONDS
、MILLISECONDS
等。 - 行为:
🔁 可通过 setKeepAliveTime() 动态修改。 ✅ 若设置 allowCoreThreadTimeOut(true),此时间也适用于核心线程。
4. workQueue
:任务队列(阻塞队列)
- 类型:
BlockingQueue<Runnable>
,用于暂存尚未执行的任务。 - 作用:当线程数达到
corePoolSize
后,新任务会被放入这个队列,而不是立即创建新线程。
常见实现:
队列类型 | 特点 | 使用场景 |
---|---|---|
ArrayBlockingQueue | 有界队列,需指定容量 | 防止资源耗尽,适合稳定负载 |
LinkedBlockingQueue | 无界队列(默认 Integer.MAX_VALUE) | 吞吐量高,但可能导致 OOM |
SynchronousQueue | 不存储元素,每个插入必须等待取出 | 直接交给线程处理,适合高并发短任务 |
PriorityBlockingQueue | 支持优先级排序 | 任务有优先级需求 |
⚠️ workQueue 不能为 null,否则抛出 NullPointerException。
🔄 线程池的工作流程(结合这5个参数)
当你调用 execute(Runnable task)
时,线程池按以下顺序处理:
- 如果当前线程数 < corePoolSize → 创建新线程执行任务(即使有空闲线程)。
- 否则,尝试将任务加入 workQueue → 如果队列未满,任务入队,等待空闲线程处理。
- 如果队列已满,且当前线程数 < maximumPoolSize → 创建“非核心线程”来处理任务。
- 如果队列已满,且线程数已达 maximumPoolSize → 触发拒绝策略(此时使用的是 AbortPolicy,会抛出 RejectedExecutionException)。
📈 参数组合示例
示例 1:固定大小线程池(Executors.newFixedThreadPool)
java深色版本new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(100));
- 核心 = 最大 = 5,线程数固定
- 使用有界队列防 OOM
示例 2:缓存线程池(Executors.newCachedThreadPool)
java深色版本new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
- 核心线程为 0,所有线程都是临时的
SynchronousQueue
不缓存任务,必须立刻有线程处理- 空闲线程 60 秒后回收
示例 3:带缓冲的弹性线程池
java深色版本new ThreadPoolExecutor(
2, // 至少保留 2 个线程
10, // 最多扩展到 10 个
30, // 多余线程空闲 30 秒后销毁
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100) // 最多排队 100 个任务
);
⚠️ 异常与校验
构造函数会在以下情况抛出异常:
条件 | 抛出异常 |
---|---|
corePoolSize < 0 | IllegalArgumentException |
maximumPoolSize <= 0 | IllegalArgumentException |
maximumPoolSize < corePoolSize | IllegalArgumentException |
keepAliveTime < 0 | IllegalArgumentException |
workQueue == null | NullPointerException |
🔧 默认值说明
这个构造函数使用的默认值:
- 线程工厂:Executors.defaultThreadFactory()创建的线程属于同一个 ThreadGroup有统一命名模式(如 pool-1-thread-1)优先级为 NORM_PRIORITY,非守护线程
- 拒绝策略:AbortPolicy(默认)直接抛出 RejectedExecutionException其他策略还有:CallerRunsPolicy:由提交任务的线程自己执行DiscardPolicy:静默丢弃DiscardOldestPolicy:丢弃队列中最老的任务,重试提交
✅ 总结:五大参数记忆口诀
参数 | 关键问题 | 记忆点 |
---|---|---|
corePoolSize | 至少留几个正式工? | 核心线程,长期存在 |
maximumPoolSize | 最多能雇多少人? | 包括临时工的总人数上限 |
keepAliveTime + unit | 临时工多久没人用就辞退? | 控制资源释放速度 |
workQueue | 没人做的活放哪? | 任务缓冲区,决定是否扩容 |
🔥 一句话总结: 这个构造函数定义了线程池的基本运行规则: 先用核心线程 → 再排队 → 排不了队就扩容 → 扩容不了就拒绝。 合理设置这 5 个参数,才能让线程池既高效又稳定。
如果你要手动创建线程池,强烈建议使用这个构造函数,而不是 Executors
工厂方法(尤其是避免使用无界队列),以防止资源失控。