首先看一下线程被销毁的代码:
// 当线程获取不到tasks, 就调用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); // 将线程从HashSet中移除
} 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);
}
}
照理说不管是核心线程还是非核心线程,blockingQueue不可能一直都有task,总有处理完的时候,一旦blockingQueue中没有task可处理,那么这个线程就一定会被remove,因为processWorkerExit方法是写在finally里面的;
// 线程池worker处理task方法
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
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();
} 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;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
那么,如何保证核心线程不退出呢?
再来明确一个概念,所谓的核心线程与非核心线程,在线程池的数据结构中并没有明确区分,只要线程池剩余的线程数小于等于corePoolSize,那么剩下的线程都可以称为核心线程;
再有,一个核心线程要想不被销毁,那么只有一种可能,那就是线程等待,等待有新的task到来;
换句话说:一旦线程池的线程个数小于等于corePoolSize,task = getTask() 是永远不会返回null的(非异常情况)。
我们来看看getTask方法是怎么处理的:
// 通过上面分析,可以得出结论:
// 1,线程数大于corePoolSize,当队列无task或者线程池状态异常时return null
// 2,线程数小于等于corePoolSize,getTask不会返回null,异常情况除外
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.
// 这个if判断也很重要,如果调用了shutdown/shutdownNow方法,那么“核心线程”也会返回null
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c); // 取线程数
// Are workers subject to culling?
// allowCoreThreadTimeOut = false
// timed = true 表示存在非核心线程
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// wc > maximumPoolSize = false 一般不会出现这种情况,所以是false
// 这个if条件成立的前提:必须存在非核心线程【关键】
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null; // 这个null就是非核心线程被销毁的罪魁祸首
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r; // 能取到任务就返回,否则设置timedOut进去死循环
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
——综上,我们总结了Java线程池的一个小细节!