前言:很多时候我们需要使用线程池来处理逻辑,但实际上线程池是如何添加线程,如何执行的呢?
0:创建线程池--略(7个参数)
1:提交线程池源码
public void execute(Runnable command) {
//判空没啥可说
if (command == null) throw new NullPointerException();
//获取核心属性
int c = ctl.get();
//workerCountOf(c)获取工作线程个数
//当前工作线程个数< 核心线程数
if (workerCountOf(c) < corePoolSize) {
//添加一个工作线程 true:核心线程 false:非核心线程
//添加工作线程有并发问题,若成功返回true,失败返回false
if (addWorker(command, true))
//成功,告辞~
return;
//添加失败,重新获取ctl,看一下当前线程情况
c = ctl.get();
}
// isRunning:线程池状态还是RUNNING嘛?
// 如果是RUNNING,就把任务扔到阻塞队列里,先排队等着
if (isRunning(c) && workQueue.offer(command)) {
//再次获取ct1属性
int recheck = ctl.get();
//再次确认线程池状态是否是RUNNING,如果不是RUNNING,将任务从阻塞队列移除
if (! isRunning(recheck) && remove(command))
//执行拒绝策略
reject(command);
//现在阻塞队列有任务,但是没有工作线程
else if (workerCountOf(recheck) == 0)
//创建一个非核心线程,去处理阻塞队列任务
addWorker(null, false);
}
// 如果任务没有扔到阻塞队列,添加非核心线程去处理任务
else if (!addWorker(command, false))
reject(command);
}
太简洁了,和我编程风格不习惯,本人优化一下,一毛一样的
//提交任务到线程池的方法
public void execute(Runnable command) {
//判空没啥可说
if (command == null) throw new NullPointerException();
//获取核心属性
int c = ctl.get();
//workerCountOf(c)获取工作线程个数
//当前工作线程个数< 核心线程数
if (workerCountOf(c) < corePoolSize) {
//添加一个工作线程 true:核心线程 false:非核心线程
//添加工作线程有并发问题,若成功返回true,失败返回false
if (addWorker(command, true)){
//成功,告辞~
return;
}
//添加失败,重新获取ctl,看一下当前线程情况
c = ctl.get();
}
// isRunning:线程池状态还是RUNNING嘛?
// 如果是RUNNING,就把任务扔到阻塞队列里,先排队等着
if (isRunning(c) && workQueue.offer(command)) {
//再次获取ct1属性
int recheck = ctl.get();
//再次确认线程池状态是否是RUNNING,如果不是RUNNING,将任务从阻塞队列移除
if (! isRunning(recheck) && remove(command)){
//执行拒绝策略
reject(command);
//现在阻塞队列有任务,但是没有工作线程
}else if (workerCountOf(recheck) == 0){
//创建一个非核心线程,去处理阻塞队列任务
addWorker(null, false);
}
//如果任务没有扔到阻塞队列,添加非核心线程去处理任务
}else if (!addWorker(command, false)){
reject(command);
}
}
好了,这回看着舒服多了,下面开始画流程图吧
2、流程图详解
3、添加工作线程的流程(addWorker方法)
源码如下:
private boolean addWorker(Runnable firstTask, boolean core) {
//goto 语句,避免死循环
retry:
// 外层自旋
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 这个条件写得比较难懂,我对其进行了调整,和下面的条件等价
// (rs > SHUTDOWN) ||
// (rs == SHUTDOWN && firstTask != null) ||
// (rs == SHUTDOWN && workQueue.isEmpty())
// 1. 线程池状态大于SHUTDOWN时,直接返回false
// 2. 线程池状态等于SHUTDOWN,且firstTask不为null,直接返回false
// 3. 线程池状态等于SHUTDOWN,且队列为空,直接返回false
//通俗的解释
//(1). 线程池已经 shutdown 后,还要添加新的任务,拒绝
//(2).(第二个判断)SHUTDOWN 状态不接受新任务,但仍然会执行已经加入任务队列的任
//务,所以当进入SHUTDOWN 状态,而传进来的任务为空,并且任务队列不为空的时候,
//是允许添加新线程的,如果把这个条件取反,就表示不允许添加 worker
if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())){
return false;
}
// 内层自旋
for (;;) {
//获得 Worker 的工作线程数
int wc = workerCountOf(c);
// worker数量超过容量,直接返回false
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)){
return false;
}
// 使用CAS的方式增加worker数量。如果 cas 失败,则直接重试
// 若增加成功,则直接跳出外层循环进入到第二部分
if (compareAndIncrementWorkerCount(c)){
break retry;
}
//再次获取 ctl 的值
c = ctl.get();
// //这里如果不想等,说明线程的状态发生了变化,继续重试
if (runStateOf(c) != rs){
continue retry;
}
// 其他情况,直接内层循环进行自旋即可
}
}
//上面这段代码主要是对 worker 数量做原子+1 操作,下面的逻辑才是正式构建一个 worker
//工作线程是否启动的标识
boolean workerStarted = false;
//工作线程是否已经添加成功的标识
boolean workerAdded = false;
Worker w = null;
try {
//构建一个 Worker,这个 worker 是什么呢?我们可以看到构造方法里面传入了一个 Runnable 对象
w = new Worker(firstTask);
//从 worker 对象中取出线程
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
// worker的添加必须是串行的,因此需要加锁
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
// 这儿需要重新检查线程池状态
int rs = runStateOf(ctl.get());
//只有当前线程池是正在运行状态,[或是 SHUTDOWN 且 firstTask 为空],才能添加到 workers集合中
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
// worker已经调用过了start()方法,则不再创建worker
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// worker创建并添加到workers成功
workers.add(w);
// 更新`largestPoolSize`变量
int s = workers.size();
//如果集合中的工作线程数大于最大线程数,这个最大线程数表示线程池曾经出现过的最大线程数
if (s > largestPoolSize){
//更新线程池出现过的最大线程数
largestPoolSize = s;
}
//表示工作线程创建成功了
workerAdded = true;
}
} finally {
//释放锁
mainLock.unlock();
}
//如果 worker 添加成功
if (workerAdded) {
//启动worker线程
t.start();
workerStarted = true;
}
}
} finally {
//如果添加失败,就需要做一件事,就是递减实际工作线程数(还记得我们最开始的时候增加了工作线程数吗)
if (! workerStarted){
addWorkerFailed(w);
}
}
return workerStarted;
}
流程图也贴出来,自己根据源码画的,有不对的地方多包涵
Worker封装和addWorkerFailed的解析--后续补上