execute()方法通过三步判断逻辑串联线程创建、队列入队与扩容决策:先读ctl拆解线程数和运行状态,再依状态分流处理任务。

直接看 execute() 方法的执行路径,就能理清整个任务调度流程。它不是靠复杂状态机驱动,而是用三步判断逻辑串联起线程创建、队列入队和扩容决策,核心就藏在 ThreadPoolExecutor 的源码主干里。
从 execute() 入口开始跟踪
任务提交的第一站是 execute(Runnable),这个方法不返回结果、不抛异常,但内部做了关键分流:
- 先读取原子变量
ctl,拆出当前线程数(workerCountOf(c))和运行状态(runStateOf(c)) - 如果线程数 corePoolSize,立刻调用
addWorker(command, true)创建核心线程执行——哪怕有空闲线程也不复用 - 否则尝试把任务塞进
workQueue.offer();成功则结束,失败说明队列已满,进入下一步 - 队列满且线程数 maximumPoolSize,再调
addWorker(command, false)创建非核心线程 - 两次
addWorker都失败,就走拒绝策略reject()
重点关注 addWorker 的两个作用
addWorker() 是真正创建并启动线程的地方,但它还承担另一个隐性职责:二次校验线程池状态。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 传入
true表示要建核心线程,会检查是否isRunning(c)且线程数未超限 - 传入
false表示建非核心线程,除状态检查外,还会判断当前线程数是否已达maximumPoolSize - 一旦通过校验,就新建
Worker对象,用threadFactory启动线程,并把firstTask绑定进去 - 注意:
Worker自身是Runnable,它的run()最终委托给runWorker(this)
看懂 runWorker 才算摸到执行本质
runWorker(Worker w) 是每个工作线程的“大脑”,它决定了线程怎么循环取任务:
立即学习“Java免费学习笔记(深入)”;
- 先执行
w.firstTask.run(),也就是初始绑定的任务 - 然后进入死循环:
while (task != null || (task = getTask()) != null) -
getTask()是关键:它从workQueue中取任务,用的是poll(keepAliveTime, unit)或take(),取决于是否是非核心线程 - 如果
getTask()返回null(比如超时或线程池关闭),循环退出,线程自然结束
别漏掉队列类型对流程的实际影响
同一个 execute() 流程,在不同队列下行为差异很大:
-
ArrayBlockingQueue:有界队列,容易触发扩容,适合控制资源上限 -
LinkedBlockingQueue(无界):任务几乎全进队列,线程数长期卡在corePoolSize,高峰易 OOM -
SynchronousQueue:不存任务,相当于“直连模式”,必须有空闲线程才能提交成功,天然倾向扩容 -
DelayedWorkQueue(ScheduledThreadPoolExecutor 专用):按延迟时间排序,getTask()会阻塞到最近到期任务

















