一文带你看懂线程池源码?ThreadPoolExecutor核心源码竟是这样实现!
文章目录
一句话了解线程池的工作原理
- ThreadPoolExecutor将任务执行委托给Worker执行
- ThreadPoolExecutor负责创建和销毁Worker
相关图示
线程池相关类图
简易流程图
详尽流程图
核心属性
// 存储线程池的状态,高3位表示线程池状态,低29位表示worker数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; // 记录表示wirker数量的bit位数,供移位使用
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 记录worker的数量
// runState is stored in the high-order bits 线程池状态
// 将 -1 移动到ctl的高3位(高3位111) 表示运行中
private static final int RUNNING = -1 << COUNT_BITS;
// 表示线程池已经关闭,不接收新任务,但能处理已添加的任务 高三位000
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 表示线程池暂停,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务 高三位001
private static final int STOP = 1 << COUNT_BITS;
// 当所有的任务已终止,ctl记录的任务数量为0 线程池就会变成TIDYING状态。高三位010
// 当线程池变为TIDYING状态时,会执行钩子函数terminated(),默认为空实现,可以由用户自定义实现
// 状态切换:当线程池在shutdown状态下,阻塞队列为null 且线程池中执行的任务也为null时,就会有shutdown -> tidying
// 当线程池在stop状态下,阻塞队列为null 线程池中执行的任务为null时,就会由 stop -> tidying
private static final int TIDYING = 2 << COUNT_BITS;
// 线程池彻底终止 就成为TERMINATED状态 高三位011
// 进入terminated条件:
// 1) 线程池不是running状态
// 2) 线程池不是tidying 或 terminated状态
// 3) 如果线程池状态是shutdown 并且 workerQueue为空
// 4) workerCount为0
// 5) 设置tidying状态成功
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
// c & ~CAPACITY 将线程池的workerCount部分剔除掉 获取运行状态信息
private static int runStateOf(int c) { return c & ~CAPACITY; }
// c & CAPACITY 获取线程池的workerCount数量
private static int workerCountOf(int c) { return c & CAPACITY; }
// 由线程池的运行状态 和 workerCount 进行或操作 获取到完整的线程池控制信息
private static int ctlOf(int rs, int wc) { return rs | wc; }
构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
// 对 线程数量参数 和 线程最大存活时间 进行合法性校验
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
// 对 阻塞队列 、 线程工厂 、 拒绝策略参数进行非空判断
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
execute()方法
public void execute(Runnable command) {
// 传入的Runnable为null 抛出异常
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
* 如果当前正在运行的线程少于corePoolSize线程,则尝试创建一个新的线程去处理
* 第一个任务
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
* 如果当前task可以成功进入队列,那么我们仍然需要再次检查是否应该创建新的线程(因为可能现有的线程上次检查之后死掉了)
* 因此,我们需要重新检查状态
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
* 如果我们不能把这个task放入队列,那么我们尝试创建一个新的线程,如果创建失败,则需要考虑拒绝该任务
*/
// 获取线程池状态
int c = ctl.get();
// worker数量比核心线程数小,直接创建worker执行任务
if (workerCountOf(c) < corePoolSize) {
// 增加一个工作线程 处理command任务
if (addWorker(command, true))
return;
// 获取线程池控制状态
c = ctl.get();
}
// 判断线程池处于运行态 并且 worker数量超过核心线程数,任务直接进入队列
if (isRunning(c) && workQueue.offer(command)) {
// 再次获取线程池控制状态进行再次检查
int recheck = ctl.get();
// 如果线程池已经不处于运行状态 则将任务拒绝
if (! isRunning(recheck) && remove(command))
reject(command);
// 为什么需要判断0值,主要是线程池构造方法中,核心线程允许为0
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 任务不可以放入队列 则创建线程
else if (!addWorker(command, false))
// 如果无法继续创建线程 则拒绝任务
reject(command);
}
addWorker()
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
/*
循环判断是否可以创建新的工作线程 退出循环的条件:
1:可以创建线程 将线程数量WorkerCount++ 跳出循环
2:线程池的生存状态不是可运行态 直接return false
*/
for (;;) {
int c = ctl.get(); // 获取线程池控制状态
int rs = runStateOf(c); // 从控制状态中获取线程池生存状态
// Check if queue empty only if necessary.
// rs >= SHUTDOWN 代表线程池不处于可运行态 直接返回false 代表无法添加新的任务
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
// 获取工作线程数量
int wc = workerCountOf(c);
// 对工作线程数量进行合法性判断
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 如果工作线程数量正常 则代表可以添加一个工作线程 将数量++ 直接跳出循环
if (compareAndIncrementWorkerCount(c))
break retry;
// 重新获取线程池控制状态
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;
boolean workerAdded = false;
Worker w = null;
try {
// 创建一个工作线程 将firstTask丢给该线程
w = new Worker(firstTask);
// 获取工作线程
final Thread t = w.thread;
// 如果工作线程不为null
if (t != null) {
// 获取lock锁 保证后续代码的线程安全
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());
// rs < SHUTDOWN : 线程池是可运行态
// 如果rs是RUNNING状态或者rs是SHUTDOWN状态并且firstTask为null,向线程池中添加线程。
// 因为在SHUTDOWN时不会在添加新的任务,但还是会执行workQueue中的任务
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 此时线程应该还未启动 在后面的start时才启动 如果此时线程就已经启动 则直接抛出异常
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();
}
if (workerAdded) {
t.start(); // 启动该线程
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
Worker()构造
Worker是ThreadPoolExecutor的内部类,继承了AbstractQueuedSynchronizer类
实现了Runnable接口
,扩展了AQS的功能,主要对线程池的Thread进行封装,使线程可以不必频繁的创建和销毁,实现的具体原理是如果有任务就一直进行while()循环,否则判断是否需要关闭线程。(该逻辑在getTask()中实现)
Worker(Runnable firstTask) {
// 设置state为-1 禁止中断,直到runWorker
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
// 创建一个线程 将worker本身作为Runnable任务对象传给线程工厂 而不是将firstTask传给线程工厂
this.thread = getThreadFactory().newThread(this);
}
Worker的run()
public void run() {
// 线程执行会调用的run方法
runWorker(this);
}
runWorker()
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
// 获取worker对象的firstTask
Runnable task = w.firstTask;
// 将worker.firstTask置空
w.firstTask = null;
// 允许中断
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
/*
保证线程不会停止 会无限的获取任务 进行执行 防止线程任务结束就停止 减少创建和销毁线程的开销
因为Java的线程采用KLT模型(用户线程和内核线程一一映射) 所以创建线程和销毁线程都需要从用户态切换到内核态
非常耗费系统资源
*/
// 如果当前处理的task不为null 或者可以从阻塞队列中取到任务
// 在getTask中如果没有获取到任务 则会将workerCount-- 但是并不会直接减少worker的数量
// 留在while跳出后,执行processWorkerExit() 关闭worker
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 执行task任务的run方法 如果出现了异常直接抛出
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
// 当任务执行完毕之后将当前执行的task置为null
task = null;
// 将完成任务的数量++
w.completedTasks++;
// 释放锁
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 从while循环中退出 证明当前线程需要被关闭
processWorkerExit(w, completedAbruptly);
}
}
getTask()
private Runnable getTask() {
// 表示上次从阻塞队列中获取任务是否超时
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
// 获取线程池控制状态
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
/*
* 如果线程池状态rs >= SHUTDOWN,也就是非RUNNING状态,再进行以下判断:
* 1. rs >= STOP,线程池是否正在stop;
* 2. 阻塞队列是否为空。
* 如果以上条件满足,则将workerCount减1并返回null。
* 因为如果当前线程池状态的值是SHUTDOWN或以上时,不允许再向阻塞队列中添加任务。
*/
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
// 获取workerCount的值
int wc = workerCountOf(c);
// Are workers subject to culling?
// 判断当前是否需要超时关闭
// 判断的标准就是:核心线程是否允许超时关闭 和 当前的线程数量超过核心线程数量
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
/*
* 出现 wc > maximumPoolSize的情况是因为可能此方法执行的同时执行了setMaximumPoolSize方法
* timed && timedOut 如果为true 表示当前操作需要进行超时控制,并且上次从阻塞队列中获取任务时发生了超时
* 接下来判断,如果有效线程数量大于1,或者阻塞队列是空的,那么尝试将workerCount减1;
* 如果减1失败,则返回重试。
* 如果wc == 1时,也就说明当前线程是线程池中唯一的一个线程了。
* */
// 如果当前线程数量 > 线程池中允许的最大线程数量 或者 需要进行超时关闭线程 并且 wc的数量大于1 或者阻塞队列为null
// 需要减少一个worker的数量
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 如果减少worker数量成功 则直接return null
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果需要进行超时关闭线程 则从workQueue中等待keepAliveTime时间后取出任务 如果没有取到就返回null
// 如果不需要进行超时关闭线程 则使用take() 一直阻塞获取任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
// 如果获取到的任务不为null 则直接返回任务
// 如果没有获取到任务 则继续循环
if (r != null)
return r;
timedOut = true; // 设置允许超时退出
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
processWorkerExit()
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
// 将当前worker从集合中移除
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试关闭线程
tryTerminate();
// 获取线程工作状态
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
// 判断线程池允许保留的最少线程数量是多少
// 如果allowCoreThreadTimeOut设置为true 代表用户允许核心线程被超时回收
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 如果允许的最少线程数量为0 但是阻塞队列并不为null 仍有任务需要处理 则将min设置为1
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 如果线程池现存的worker数量 >= min worker数量 直接return
if (workerCountOf(c) >= min)
return; // replacement not needed
}
// 如果当前worker数量小于系统要求的min worker数量 则会再创建一个worker
addWorker(null, false);
}
}