该文章主要介绍了线程池如何进行任务的执行以及线程池超时收缩的策略
Woker继承Runnable,它的run方法只调用了runWorker方法。
public void run() {
runWorker(this);
}
runWorker执行两种任务:
1、Worker初始化时的firstTask(可能为null)
2、前者为null时,从工作任务中获取任务进行执行
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();
// Thread.interrupted是一个本地方法调用,可能耗时操作?所以进行recheck?
if ((runStateAtLeast(ctl.get(), STOP) ||
//清空中断标志位
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())//没有二次中断
wt.interrupt();//需要自己的线程通过isInterrupted或者Thread.interrupted来响应中断,否则,这些任务可能永远不会停止
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);
}
}
从源码可见在runWorker中,没有响应中断的实现。所以,就算调用shutDownNow,对所有工作线程执行interrupt操作,如果还有长时任务在执行,而且该任务没有抛出异常或者处理中断的逻辑,线程池也无法到达TERMINATED状态,jvm进程也无法结束(因为DefaultThreadFactory默认创建非Deamon线程)。
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 (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//1、 STOP || TIDYING || TERMINATED
//2、 SHUTDOWN && workQueue.isEmpty
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
// 线程超时处理
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源码中可以看出,getTask返回null意味着调用工作线程退出。
while (task != null || (task = getTask()) != null) {
...
}
getTask返回null的情况:
1、线程池状态为 STOP、TIDYING、TERMINATED;
2、线程池状态为SHUTDOWN且工作任务队列为空;
3、第一次poll超时(keepAliveTime)返回,这个值一般作用于超出corePoolSize的那部分线程。如果设置了线程allowsCoreThreadTimeOut(true),该标志默认为false,则作用于workerCount - 1个线程,换句话说,直至最后只剩一个空闲线程;(下面逻辑为超时逻辑)
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
结合runWorker和getTask源码可以看出,工作线程退出只能是如下任意条件:
1、getTask返回null
2、task.run处理中断或者包含sleep、wait等可中断方法,并且向上传递中断异常;
3、task.run其它异常
4、回调beforeExcute、afterExecute方法抛出异常