目录
变量含义
-
ctl
既表示workerCount(有效线程数),也表示runState(线程池状态)。其值为负数时表示线程池状态,为正数时表示线程数。- ctl 的初始值:-536870912
- | 高位 | 低位 |
- | -536870912 —> 0 —> 536870912 |
- | 线程状态 | 线程数量 |
-
runState
的几个常量实际上是范围,是边界值,并非固定的值,只不过这几个状态的范围有数值顺序,可以用大于、小于比较。RUNNING
正常接收任务SHUTDOWN
不接收新任务,继续处理已存在的任务STOP
不接收新任务,也不会处理队列中的任务,同时中断正在进行的任务TIDYING
过渡状态,表示当前线程池即将终止。已经执行完shutdown
或shutdownNow
方法,准备终止线程池TERMINATED
表示线程池已终止,要执行terminated方法才到这个状态
-
runStateOf
方法:线程池状态,返回负数说明是RUNNING,0为SHUTDOWN,理论上不会返回正数。 -
workerCountOf
方法:线程数量,随着ctl++
,返回值也是0开始递增,直到536870911 & 536870911 = 536870911
。workerCount不包含队列中的任务。 -
Worker对象
继承自AQS,可以方便的实现工作线程的终止操作。 -
COUNT_BITS
int变量:长度。29,方便做位运算。 -
CAPACITY
int变量:容量。线程池中线程池的最大数量。 -
SHUTDOWN --> TIDYING
队列为空,工作线程为空时。 -
STOP --> TIDYING
工作线程为空时。 -
TIDYING --> TERMINATED
内部调用方法,状态变为TERMINATED。
源码解析
execute
execute解析,线程池执行流程
// 这个方法没有加锁,所以有多次recheck的操作
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// 分3步进行:
// 1. 如果正在运行的线程少于corePoolSize,尝试新开启一个线程
// 将command作为它的第一个任务。对 addWorker 的调用
// 以原子方式检查 runState 和 workerCount。
//
// 2. 如果一个任务成功进入队列,仍然需要检查是否应该添加一个线程
// 可能期间其他线程调用线程池的shutdown 或 terminate相关方法。
// 因此,要重新检查状态,
// if 不是running,移除刚入队的任务。
// else-if 线程数为0(因为是else-if,此时必定是running),则启动一个新线程。
//
// 3. 经过以上2步,既无法加入队列,也无法添加新线程,则要么shutdown 要么已饱和
// 此时拒绝该任务
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
// 这里 可能因为并发等原因,导致创建线程并add失败,重新获取ctl
c = ctl.get();
}
// Q-1
// 如果是STOP或SHUTDOWN,不接收新任务。如果是RUNNING,到这里表示创建核心线程池失败,要加入队列
if (isRunning(c) && workQueue.offer(command)) {
// 怕出现并发问题
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
// 结论:这个if表示. 有任务,但没有工作线程来处理,需要新建一个任务为空的工作线程来处理队列中的任务
// 这一步可能出现的原因:如果线程池只有一个线程T1在运行,main走到这里,T1运行完成,
// ctl执行 -1 操作,此时线程数为0,结果为true 进入if。
// 为什么第一个参数为null?
// 在addWorker时,任务已经入队,在runWorker方法中,
// 如果worker的firstTask为null,那么会从workQueue队列里取任务执行,
// 此处传null让 addWorker 方法内部有机会执行 t.start(),从而之行runWorker方法
// 这里可以得出,队列中的任务不包含在workerCount中
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 到这里有以下2种情况:
// 1. running状态,入队失败(队列已满)。创建非核心线程来处理任务
// 2. 不是running状态,即c >= SHUTDOWN
// 直接调用 addWorker 方法,是因为里面有判断ctl状态的方法,为SHUTDOWN返回fasle
else if (!addWorker(command, false))
reject(command);
}
问题
- 为什么代码
Q-1
处要使用workQueue.offer
而不是put
等阻塞方法?
答:一般是主线程调用execute方法,如果阻塞,影响后续代码执行。
addWorker
进入这个方法有2种情况:
- 核心线程数小于正在执行任务的线程数。
- 核心线程数已满 && 当前线程数<=最大线程数 && 任务入队成功。
private boolean addWorker(Runnable firstTask, boolean core) {
// for:CAS更新线程池数量
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 1. 不是RUNNING状态
// 2. 且,线程池状态不等于SHUTDOWN or firstTask为null or 队列为空
// 必须是SHUTDOWN、firstTask==null、workQueue==空,才走else,对应execute的最后一次调用
// 满足上述条件直接返回false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
// 线程数量大于CAPACITY or (线程数量大于核心线程数or最大线程数),返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// ctl自增workCount,成功则结束整个循环
if (compareAndIncrementWorkerCount(c))
break retry;
// workCount更新失败,重新获取ctl的值(出现并发了)
c = ctl.get(); // Re-read ctl
// 状态已经改变,则继续外层循环。否则continue内层循环重试
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
// 上面主要是对 worker 数量做原子+1 操作,下面的逻辑才是正式构建一个 worker
// 工作线程是否启动标识
boolean workerStarted = false;
// 工作线程是否添加成功标识
boolean workerAdded = false;
Worker w = null;
try {
// 构建一个worker,里面是任务
w = new Worker(firstTask);
// 从worker里取出线程对象
final Thread t = w.thread;
if (t != null) {
// 线程池全局锁,防止当前线程添加任务时,其他线程kill了线程池
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());
// 线程池是RUNNING[或 是SHUTDOWN但传过来的空任务 与上面对应,创建空线程来处理队列的任务],才能添加到队列中
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 任务刚来,还未添加启动,就已经alive状态,这里不对,所以要抛异常
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 加入worker集合。workers是一个HashSet
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;
}
问题
addWorker做了2件事,1-递增ctl;2-task加入 workers集合并start(线程池中的线程)
- 传入的Runnable类型的任务紧接着就进行start了,那么为什么还要workers.add(w)放入集合呢,workers集合存在的意义是什么呢?(addWorker方法在什么线程里执行的?)
答:为了保存当时的thread和worker,后续可能会对thread和worker进行加锁和中断,addWorker和runWorker是并行关系,需要随时监视shutdown,shutdownNow,terminate的动作。 - 线程池(ThreadPoolExecutor)中存放的是线程吗?
答:不是,是一堆Worker,Worker既不是thread线程也不是要执行的任务。
new Worker(Runnable firstTask)
- Worker实现AQS,内部实现是一个独占锁,不允许重入,为了针对不同的worker进行中断。
- 为什么不用Lock而是需要实现AQS,主要是不能允许重入的,在中断线程时,竞争锁资源。
Worker(Runnable firstTask) {
// 刚初始化,不允许被中断
setState(-1);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
runWorker [woker.run()]
addWorker的t.start()触发了该方法。执行任务的流程,并且做了能否中断的判断(Worker的state状态)
final void runWorker(Worker w) {
// 获取当前线程并拿到任务
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
// 任务归位
w.firstTask = null;
// worker的lock用于区分线程是否空闲的(AQS的release)
w.unlock(); // allow interrupts
// 是否发生了意外
boolean completedAbruptly = true;
try {
// 任务不空。直接执行
// 任务空,通过getTask()获取任务
while (task != null || (task = getTask()) != null) {
// worker加锁,这样即便shutdown 任务也不会中断
w.lock();
// 如果线程池正在停止,确保线程被中断;如果不是,确保线程不会被中断,
// 第二种情况时,需要重新检查以清除中断时shutdownNow的竞争。
// 上面说SHUTDOWN不会中断,但STOP/TIDYING/TERMINATED时:中断任务
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
// 子类自定义实现
beforeExecute(wt, task);
Throwable thrown = null;
try {
// do 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;
// 完成的任务数+1
w.completedTasks++;
// worker的state设置为0,表示调用shutdown可以中断
w.unlock();
}
}
completedAbruptly = false;
} finally {
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);
// 线程池状态不是RUNNING,且,STOP/TIDYING/TERMINATED or 队列为null。移除当前工作线程
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
// 递减工作线程数量。这里并没有从workers里remove,remove是在runWorker方法的finally代码块里
decrementWorkerCount();
return null;
}
// ================判断工作线程数量 ==============
int wc = workerCountOf(c);
// 是否允许核心线程池超时 or 工作线程数量 > 核心线程数
// 第二种情况,判断是否需要干掉自己
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if (
// 工作线程数大于最大线程数(基本不可能)
// or 工作线程数大于核心线程数,且 该工作线程已经超时
(wc > maximumPoolSize || (timed && timedOut))
// 且 干掉自己后 至少还有一个工作线程
// or 队列为空
// ========以上满足则会干掉当前线程
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
// ================从工作队列中获取任务 ==============
try {
// 核心线程允许超时 or 此时是非核心线程在干活。走poll,超时就返回
// 核心线程不允许超时 and 核心线程在干活。走take方法,一直阻塞
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
// 没拿到任务,表示走的是poll,从队列获取任务超时,即达到了工作线程的keepAliveTime
timedOut = true;
} catch (InterruptedException retry) {
// take时被中断,再来一遍
timedOut = false;
}
}
}
processWorkerExit
移除当前工作线程
- 当前工作线程需要被清理
- 当前线程池状态不对,需要移除
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// before或after钩子函数抛出了异常(不是getTask方法调用)
if (completedAbruptly)
// 递减工作线程数
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 记录当前线程池一共处理过多少任务。前面加锁跟这个有关
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试将线程池关闭,(--> TIDYING --> TERMINATED)
tryTerminate();
int c = ctl.get();
// 线程池状态RUNNING or SHUTDOWN。否则里面的代码无需执行
if (runStateLessThan(c, STOP)) {
// 是否有异常。completedAbruptly = false:没有异常,true:有异常
// if 正常状态移除当前工作线程
if (!completedAbruptly) {
// 允许最小的核心线程数
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 最小的核心线程数是0,and 队列不为空。设置工作线程最小值为1,表示至少要有1个线程去处理任务
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 还有工作线程在线程池中,确保任务有线程执行。直接return,否则再addWorker一个null任务的线程
if (workerCountOf(c) >= min)
return; // replacement not needed
}
// 不是正常状态下移除当前工作线程,
// or 队列有任务但没有工作线程了。需要新增一个工作线程处理队列中的任务
addWorker(null, false);
}
}