mentWorkerCount();
// 返回null,交接processWorkerExit移除当前工作线程
return null;
}
// ==================判断工作线程数量======================
// 拿到工作线程数
int wc = workerCountOf(c);
// allowCoreThreadTimeOut: 是否允许核心线程超时(默认false)
// 工作线程是否大于核心线程
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 工作线程是否已经大于最大线程数
// 工作线程大于核心线程数,并且当前线程已超时
// 尝试干掉当前线程
if ((wc > maximumPoolSize || (timed && timedOut))
// 工作线程数大于1,或者工作队列为空
// 如果工作线程队列,就干掉自己
// 如果工作线程数大于1,就干掉自己
&& (wc > 1 || workQueue.isEmpty())) {
// 基于CAS的方法移除当前线程,只有一个线程会CAS成功
if (compareAndDecrementWorkerCount(c))
// 返回null,交接processWorkerExit移除当前工作线程
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方法中processWorkerExit方法
// 移除当前工作线程
private void processWorkerExit(Worker w, boolean completedAbruptly) {
/*
* 如果执行processWorkerExit方法的操作不是getTask中的操作,
* 是直接因为异常引起的。(一般是勾子函数抛出异常导致的)
*/
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();
}
// 尝试将线程池关闭(到TIDYING过度状态 - TERMINATED销毁状态)
tryTerminate();
// 重新获取ctl
int c = ctl.get();
// 判断当前状态是否小于STOP, 能进入说明是RUNNING、 SHUTDOWN
if (runStateLessThan(c, STOP)) {
// 如果是正常状态移除当前工作线程
if (!completedAbruptly) {
// 核心线程数最小值 ,允许核心线程超时就是0
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 如果工作队列中的任务不为空,设置工作线程的最小值为1
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 还有工作线程在线程池中
if (workerCountOf(c) >= min)
return; // replacement not needed
}
// 1. 说明是不正常的方式移除当前工作线程,那需要在添加一个非核心线程
// 2. 线程池工作队列不为空,并且没有工作线程,需要在添加一个非核心线程
addWorker(null, false);
}
}
线程池为啥要构建空任务的非核心线程?
- 第一个:在 execute 方法中有个判断工作线程是否为0,是就添加一个空任务的非核心线程;
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
- 第二个:在工作线程 Worker 启动后,工作线程会运行 runWorker 方法,该方法中有个操作,当工作线程结束之后会执行 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;
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
综合上诉,Java它有一个这样的场景:
在初始化线程池的时候可能设置线程池的核心线程数为0 或者 设置allowCoreThreadTimeOut(默认false)为ture导致核心线程超时释放,存在没有核心线程的情况。
当我们把任务添加到阻塞队列之后,没有工作线程导致阻塞队列任务堆积,直到后续有新任务加入才会去创建工作线程。
/**
* If false (default), core thr