一、ThreadPoolExecutor中的核心变量和内部类
1.1 ctl
线程池内部使用ctl来维护线程状态(runState)和线程数量(workerCount),高三位表示线程线程状态(runState),低29位表示线程数量(workerCount)
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
1.2 内部类Worker
Worker是线程池中为了维护线程的状态并维护线程的生命周期而设计的。
这worker类实现了Runnable接口,并持有一个线程和一个初始化任务。
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
// worker持有的线程,可以为空
final Thread thread;
//初始化任务
Runnable firstTask;
/*省略*/
}
二、execute()分析
所有的任务调度都由有execute()进行完成的。主要有三部分
- 判断当前的工作线程数是否小于核心线程数
- 判断线程池是否为Running状态并且可以加入到缓存队列中
- 判断是否可用尝试添加一个新的线程
详细分析
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// 获取ctl值(包括了线程状态和线程数量)
int c = ctl.get();
// workerCountOf(): 根据clt获取线程数量
// 判断当前线程数是否小于核心线程数
if (workerCountOf(c) < corePoolSize) {
/**
* addWorker(): 尝试增加核心线程或者非核心线程以执行任务(区分core)
* @param firstTask 表示线程启动后第一个执行的任务
* @param core 判断新添加的线程是否应该被视为核心线程(true)还是非核心线程(false)。
*/
if (addWorker(command, true))
return;
// 再次获取值
c = ctl.get();
}
// 如果当前的线程池还在运行并且加入缓存队列成功
if (isRunning(c) && workQueue.offer(command)) {
// 获取clt
int recheck = ctl.get();
// 如果线程池状态不是运行状态就从队列移除任务并拒绝执行
if (! isRunning(recheck) && remove(command))
reject(command);
// 如果活跃的线程为空时
else if (workerCountOf(recheck) == 0)
// 尝试添加一个非核心线程来检查队列
addWorker(null, false);
}
//如果不能直接执行也不能入队,尝试添加非核心线程执行任务,失败则拒绝任务
else if (!addWorker(command, false))
reject(command);
}
其执行流程如下图所示:
三、addWokret()
addWokert方法只要是负责创建新线程,并启动线程
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
// 获取ctl
int c = ctl.get();
// 获取当前线程池的状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
// 1、如果当前线程池的状态大于等于SHUTDOWN,则返回false
// 2、如果当前当前线程池的状态等于SHUTDOWN,并且firstTask为空,缓存队列为空,则返回false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
// 获取线程中当前活跃的线程数量
int wc = workerCountOf(c);
// 检查线程容量
if (wc >= CAPACITY || // 如果达到线程池的最大容量
wc >= (core ? corePoolSize : maximumPoolSize)) // 或者达到核心线程池大小(如果`core`为`true`)
return false;
// 通过循环加cas修改ctl的值,增加线程数量
if (compareAndIncrementWorkerCount(c))
// 表示新增成功,跳出循环
break retry;
// 再次获取ctl的最新值
c = ctl.get(); // Re-read ctl
// 判断线程池状态是否一致
if (runStateOf(c) != rs)
// 重新执行循环
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
// 标识线程是否已经执行
boolean workerStarted = false;
// 标识线程是否加入hashSet(存储线程的容器)
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 {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
// 获取线程池中的线程数量
int s = workers.size();
if (s > largestPoolSize)
// 记录线程池中出现的线程数
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 判断是否加入hashSet中
if (workerAdded) {
// 启动线程
t.start();
// 标识任务已经执行
workerStarted = true;
}
}
} finally {
// 如果线程还没有执行
if (! workerStarted)
//移除工作线程
addWorkerFailed(w);
}
return workerStarted;
}
其执行流程如下图所示:
图片来源于:Java线程池实现原理及其在美团业务中的实践