线程池

逐行、深入地详解 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.SECONDSMILLISECONDS 等。
  • 行为
🔁 可通过 setKeepAliveTime() 动态修改。 ✅ 若设置 allowCoreThreadTimeOut(true),此时间也适用于核心线程。


4. workQueue:任务队列(阻塞队列)

  • 类型BlockingQueue<Runnable>,用于暂存尚未执行的任务
  • 作用:当线程数达到 corePoolSize 后,新任务会被放入这个队列,而不是立即创建新线程。

常见实现:

队列类型特点使用场景
ArrayBlockingQueue有界队列,需指定容量防止资源耗尽,适合稳定负载
LinkedBlockingQueue无界队列(默认 Integer.MAX_VALUE)吞吐量高,但可能导致 OOM
SynchronousQueue不存储元素,每个插入必须等待取出直接交给线程处理,适合高并发短任务
PriorityBlockingQueue支持优先级排序任务有优先级需求
⚠️ workQueue 不能为 null,否则抛出 NullPointerException。


🔄 线程池的工作流程(结合这5个参数)

当你调用 execute(Runnable task) 时,线程池按以下顺序处理:

  1. 如果当前线程数 < corePoolSize → 创建新线程执行任务(即使有空闲线程)。
  2. 否则,尝试将任务加入 workQueue → 如果队列未满,任务入队,等待空闲线程处理。
  3. 如果队列已满,且当前线程数 < maximumPoolSize → 创建“非核心线程”来处理任务。
  4. 如果队列已满,且线程数已达 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 < 0IllegalArgumentException
maximumPoolSize <= 0IllegalArgumentException
maximumPoolSize < corePoolSizeIllegalArgumentException
keepAliveTime < 0IllegalArgumentException
workQueue == nullNullPointerException


🔧 默认值说明

这个构造函数使用的默认值:

  • 线程工厂:Executors.defaultThreadFactory()创建的线程属于同一个 ThreadGroup有统一命名模式(如 pool-1-thread-1)优先级为 NORM_PRIORITY,非守护线程
  • 拒绝策略:AbortPolicy(默认)直接抛出 RejectedExecutionException其他策略还有:CallerRunsPolicy:由提交任务的线程自己执行DiscardPolicy:静默丢弃DiscardOldestPolicy:丢弃队列中最老的任务,重试提交


✅ 总结:五大参数记忆口诀

参数关键问题记忆点
corePoolSize至少留几个正式工?核心线程,长期存在
maximumPoolSize最多能雇多少人?包括临时工的总人数上限
keepAliveTime + unit临时工多久没人用就辞退?控制资源释放速度
workQueue没人做的活放哪?任务缓冲区,决定是否扩容
🔥 一句话总结: 这个构造函数定义了线程池的基本运行规则: 先用核心线程 → 再排队 → 排不了队就扩容 → 扩容不了就拒绝。 合理设置这 5 个参数,才能让线程池既高效又稳定。


如果你要手动创建线程池,强烈建议使用这个构造函数,而不是 Executors 工厂方法(尤其是避免使用无界队列),以防止资源失控。