先看下如何获取任务的
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.
说明点:
有两种情况将一直减少,那么减少到什么时候终止呢?
1、rs == STOP 时,此时不接收新的任务,也不处理队列的中的任务
2、rs == SHUTDOWN时,此时不接收新的任务,队列也是空的,
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
说明点:
核心线程也可以被销毁通过设置allowCoreThreadTimeOut=true
超过核心线程和最大线程数控制线程的回收时通过调用调用队列的不同方法来实现的 一个是固定时间取 一个是一直阻塞
1、timed=false 其余的情况都是false 这是都是阻塞的从队列里获取任务
2、timed = true 有两种情况:
1)、通过调用方法allowCoreThreadTimeOut设置
如果allowCoreThreadTimeOut=true时,直接调用workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
取到任务返回,没有取到返回null
2)、工作线程大于corePoolSize核心线程数
如果allowCoreThreadTimeOut=fasle时, corePoolSize < wc < maximumPoolSize这时时需要对线程进行回 收,通过workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)来取任务, 使用字段keepAliveTime来控制超时是时间,如果取到任务,则返回,否则timedOut=true,如果wc > 1 || workQueue.isEmpty() 则进入下面的if判断,如果调用方法compareAndDecrementWorkerCount减少工作线程数失败,说明此时的线程数修改,重新进入循环,正常的情况下并返回nul,重新返回继续执行runWorker中循环判断,这是已经释放了锁,进入方法processWorkerExit,减少工作线程数,若此时的wc <= corePoolSize,又恢复正常的核心线程数。
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
接下来分析下线程池最核心的方法runWorker,通过有限的线程驱动足够的任务
说明点:
假设存在多个线程进入到这个方法,A,B,C,D....,因为如果进入这个方法都是由不同的线程进行驱动的,到这里方法的每一个变量都是线程的在方法栈中,唯一存在竞争是锁lock的竞争,每次循环再次进入获取到任务都需要重新获取锁, 获取到锁的线程执行自己的任务,是不能被中断的
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;// 将任务设置为null,表明这个线程这个线程可能驱动其它任务,此时线程将不和任何任务绑定
w.unlock(); // allow interrupts 那么这里释放锁是如何理解呢?意思就是说这个线程可以中断,使锁的状态为0,后面的代码正常执行
boolean completedAbruptly = true;
try {// 如果task为null,则从队列里获取任务
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
/** 下面两种情况将会中断当前正在执行任务的线程:
* 1、线程池的状态大于等于STOP,那么只有SOPT和TIDYING 并且当前线程没有被中断
* 2、或者该线程已经被中断了,但是线程池的状态大于等于STOP并且当前线程没有被中断
*/
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();// 真正执行任务的地方
} 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;
w.completedTasks++;// 此时是线程安全的
w.unlock();
}
}
completedAbruptly = false;// 这个标记是不是永远为false??? 如果不是哪里会出现别的情况?
} finally {
processWorkerExit(w, completedAbruptly);
}
}
processWorkerExit
runWorker最后会调用一些该方法进行一些清理工作
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;
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试中断
tryTerminate();
int c = ctl.get();
// SHUTDOWN和RUNNING两状态
if (runStateLessThan(c, STOP)) {
// 在没有异常的情况下
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
/**
* 两种情况
* 1、allowCoreThreadTimeOut=true 开启了 可以保留至少一个工作线程
* 2、min为核心线程数corePoolSize时保留,核心的工作线程数
*/
if (workerCountOf(c) >= min)
return; // replacement not needed 直接返回
}
// 发生异常新增一个空任务 按我的理解这段代码应该不会执行???
addWorker(null, false);
}
}
tryTerminate方法
这个方法主要是结束线程池
final void tryTerminate() {
for (;;) {
int c = ctl.get();
/** 下面3种情况停止中断
* 1、线程池正在运行
* 2、线程池的状态是TIDYING或TERMINATED
* 3、线程池状态是SHUTDOWN但是队列不为空
*/
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
// 工作线程数不为0 中断空闲线程 这里是怎么判断线程是否是空闲的线程呢?
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();// 在什么情况下会进行等待呢?
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
我们来回答一下上面的问题 在什么情况下会进行等待呢?
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
if (nanos <= 0)
return false;
// 可以看到在这里惊醒等待
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
那如何理解中断线程空闲的线程呢?先看源代码
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
// 没有中断并且获取到了锁
// 可以看到,程序执行到这里了,说明已经是没有什么任务了 那么给他一个中断标识
if (!t.isInterrupted() && w.tryLock()) {// 那这里又是怎么理解呢?
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
addWorker方法
该方法主要是添加任务并驱动任务
这里大家会不会觉得有疑问?空任务加入的目的是什么?在前面我们可以看到这样做可以启动一个线程
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
// 获取线程的状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
/**
* 这里着重理解下:
* 1、线程池状态为STOP,TIDYING 停止执行
* 2、如果运行状态是SHUTDOWN,firstTask != null 继续执行
* 3、如果运行状态是SHUTDOWN,firstTask != null,队列还有任务 继续执行
* 4、如果运行状态是SHUTDOWN,firstTask != null,队列没有任务 继续执行
* 5、如果运行状态是SHUTDOWN,firstTask == null,队列是空的 继续执行
*/
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 {// 创建一个新线程驱动任务
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();
}
if (workerAdded) {
t.start();// 启动线程
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
线程的入口方法execute
public void execute(Runnable command) {
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.
*
* 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.
*
* 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.
*/
int c = ctl.get();
// 工作线程小于核心线程数
if (workerCountOf(c) < corePoolSize) {
// 创建一个新的线程来驱动 core主要用来判断当前线程数是否大于核心和最大线程数
if (addWorker(command, true))
return;
c = ctl.get();
}
// 大于核心线程数 则加入到队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 线程池已经停止了将任务移除
if (! isRunning(recheck) && remove(command))
// 调用相应的拒绝策略
reject(command);
// 增加一个空任务 启动线程池
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 加入队列失败启动一个新的线程驱动任务 线程池停止了会直接返回
// 工作线程数大于容量或者如果是核心将大于核心线程数 如果是非核心将大于最大线程数据返回
// false
else if (!addWorker(command, false))
reject(command);
}
shutdown():不会停止正在执行的任务而是让线程自动完成任务
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查访问权限
checkShutdownAccess();
// 等待到SHUTDOWN状态
advanceRunState(SHUTDOWN);
// 中断所有空闲状态
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
shutdownNow():等待线程池到STOP状态,非运行的状态都将传递中断信号,同时将队列的任务取出
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
// 提升到STOP状态
advanceRunState(STOP);
// 中断非运行状态下所有线程
interruptWorkers();
// 将队列中的任务取出
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}