runWorker方法相对比较简单,主要有个循环
try{
while (task != null || (task = getTask()) != null) {
…
try {
…
task.run();
} finally {
task = null;
…
}
}
}finally {
processWorkerExit(w,completedAbruptly);
}
可以看到task
!=null 即启动线程时传进来的第一个任务,执行完之后,runWorker并不会退出,而是线程复用继续getTask()从队列中获取任务,直至所有任务都执行完,getTask()返回空。
getTask()也比较简单,主要代码就是:
Runnable r = timed ?
workQueue.poll(keepAliveTime,
TimeUnit.NANOSECONDS) :
workQueue.take();
如果设置了超时就poll,否则就take()一直阻塞,直到从队列中获取到任务为止。一般情况,如果线程池数大于core的时候,需要回收(poll),线程数等于core时核心线程是不会被回收的,就一直阻塞等待任务加入队列。
processWorkerExit(w, completedAbruptly); 这个方法,是在所有任务都已执行完或发生异常时执行,completedAbruptly=true 表示异常退出,false表示正常退出。
processWorkerExit方法相对来说也挺好理解:
1、线程池完成任务数增加当前线程的完成任务数,workers集合移除当前worker
completedTaskCount += w.completedTasks;
workers.remove(w);
2、tryTerminate(); //尝试结束线程池
3、这时候线程池状态还是小于STOP:
如果当前线程是异常退出,则需要再启动一个线程继续去执行任务队列的任务;
正常退出逻辑:min:线程池最小空闲数,允许核心线程超时则为0,否则为核心线程池大小corePoolSize,而如果min=0并且任务列表不为空,则min=1即至少要保证一个线程来处理队列中的任务。if
(workerCountOf(c) >= min) 即当前线程池中的工作线程大于最小空闲数,就不用担心了,直接返回。否则就跟异常退出一样,需要再启动一个线程继续执行队列中的任务。总结一下就是以下三种情况需要新增一个Worker来替代原来的:
// 1. 用户执行的任务发生了异常
// 2. Worker数量比线程池基本大小要小
// 3. 阻塞队列不空但是没有任何Worker在工作
if (runStateLessThan(c, STOP)) {
if(!completedAbruptly) {
intmin = allowCoreThreadTimeOut ? 0 : corePoolSize;
if(min == 0 && ! workQueue.isEmpty())
min= 1;
if(workerCountOf(c) >= min)
return;// replacement not needed
}
addWorker(null,false);
}