1. 生命周期
- RUNNING:运行中。能够接受新任务,以及对新添加的任务进行处理
- SHUTDOWN:已开始关闭。不可以接受新任务,但是可以对已添加的任务进行处理
- STOP:已停止。不接收新任务,不处理已添加的任务,并且会中断正在处理的任务
- TIDYING:正在清理资源。执行钩子函数terminated(),默认空实现
- TERMINATED:已完全关闭
线程池用AtomicInteger类型的ctl字段记录线程池中的任务数量和线程池的状态两个信息,共32位,前3位表示线程池状态,后29位表示线程池中的任务数量
2. 构造参数
- 核心线程数:常驻线程数量,空闲时也存活
- 最大线程数:允许的最大线程数,只有在工作队列已满且仍有新任务提交时启用
- 线程工厂:允许自定义线程的创建行为,如命名规则、优先级调度、守护线程、异常处理等,默认使用Executors.defaultThreadFactory()
- 拒绝策略:RejectedExecutionHandler的实现,当线程池已经关闭、达到最大线程数且等待队列已满时执行
- 阻塞等待队列:BlockingQueue类型队列
- 线程存活时间:非核心线程空闲时可以保持存活的时间
- 时间单位:秒、毫秒等
3. 执行流程
3.1 execute
- 首先判断运行线程数,小于核心线程数则尝试启动线程,成功则直接返回
- 其次判断线程池状态,在运行中就加入阻塞等待队列。此时有两个特殊检验:
- 如果线程池状态突然变为不是运行,且该任务已被其他线程执行因此无法从阻塞队列中remove,则执行拒绝策略
- 如果线程池状态是运行中,但工作线程数为0,则需要启动新线程,之后再从阻塞队列中取出任务执行
- 如果线程池状态不在运行中,或加入阻塞等待队列失败,则尝试启动新线程,若也失败,则执行拒绝策略
public void execute(Runnable command) {
// 如果无指令,则空指针
if (command == null)
throw new NullPointerException();
// 获取ctl(前3位表示线程池状态,后29位表示运行线程数)
int c = ctl.get();
// 如果运行线程数小于核心线程数,则添加Worker尝试启动新线程执行任务,成功则返回,不成功则获取最新的ctl,根据新的线程池状态和等待队列处理任务
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 如果线程池状态在运行中,且等待队列能够加入
if (isRunning(c) && workQueue.offer(command)) {
// 加入队列后,再获取ctl
int recheck = ctl.get();
// 如果线程池状态不在运行中,则从队列中移除,拒绝
// PS:如果remove失败,则说明该任务在其他线程执行了,此线程跳过,无需执行
if (! isRunning(recheck) && remove(command))
reject(command);
// 如果线程池状态在运行中,工作线程=0,按理应该新建线程执行任务,但任务已经加入等待队列,因此新建空线程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
} // 如果线程池不在运行中,或等待队列无法加入,则尝试启动新线程,若失败,则拒绝
else if (!addWorker(command, false))
reject(command);
}
3.2 addWorker
循环retry,判断是否满足新增Worker的条件:
- 首先判断线程池状态是否可用:如果线程池状态已关闭 或 正在关闭且有等待队列有待执行的线程,则直接返回false,代表无法加入新的线程
- 其次判断线程数量:如果工作线程大于容量 或 工作线程大于最大线程数,则也直接返回false
- 循环CAS(手写自旋锁):通过校验后,则说明可以增加线程任务,使用CAS尝试增加工作线程数ctl,成功则退出循环。失败则重试CAS,如果线程池状态改变,则重试retry
新增Worker:
- 加锁,确保线程安全
- 获取线程池状态,如果线程池状态在运行中 或 正在关闭中且传入的任务为空,则将任务加入workers线程集合中,并更新最大线程记录到workers集合中,设置workerAdded为true代表成功加入执行列表
- 最后新Worker的线程开始执行,设置workerStarted为true,代表启动成功
private boolean addWorker(Runnable firstTask, boolean core) {
// retry标签定义可重试的代码块,用于在CAS操作失败时重新循环判断条件
retry:
for (;;) {
// 获取线程池状态
int c = ctl.get();
int rs = runStateOf(c);
// 如果线程池状态已关闭 且 (线程池正在关闭 且 无任务 且 等待队列不为空)则直接返回false,表示无法添加新的工作线程
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN && firstTask == null &&! workQueue.isEmpty()))
return false;
for (;;) {
// 获取当前工作线程数
int wc = workerCountOf(c);
// 如果工作线程数大于容量 或 大于核心和最大线程数,则直接返回false,表示无法添加新的工作线程
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 使用CAS尝试增加工作线程数,成功则退出循环
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// 如果线程池状态变更,则退出当前循环,,重试retry循环
if (runStateOf(c) != rs)
continue retry;
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 加锁确保线程安全
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
// 如果线程池在运行中 或 线程池正在关闭且任务为空,则将任务加入workers线程集合中,并更新最大线程记录
if (rs < SHUTDOWN ||(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 如果线程成功加入workers集合,则开始执行线程
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
// 如果线程未成功启动,则将线程从工作线程中移出,更改工作线程数
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}