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())) {
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;
}
}
}
这是ThreadPoolExecutor的getTask()方法,其中比较重要的片段:
重点:workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :workQueue.take();
timed参数是什么? (wc为当前线程数)
timed参数是用来判断当前线程数是否大于核心线程数,如果大于,就执行poll方法,否则执行take方法,因为这些大于核心线程数的线程如果没有任务是有可能被回收处理的,而take()方法会使线程一直被阻塞住,直到有任务来,不会对线程进行回收。
workQueue是什么:private final BlockingQueue<Runnable> workQueue;是定义的阻塞队列
阻塞队列的两个取出元素的方法poll()和take(),前者是一个非阻塞方法,如果当前队列为空,直接返回,而take()是一个阻塞方法,即如果当前队列为空,阻塞线程,封装线程到AQS的条件变量的条件队列中,而上面的方法是一个介于二者之间的方法。
然后看这个阻塞队列方法:E poll(long timeout, TimeUnit unit)
Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an element to become available.
所以:我们的线程在获取任务时,如果队列中已经没有任务,会在此处阻塞keepALiveTime的时间,如果到时间都没有任务,就会 return null(不是直接返回null,是最终),然后在runWorker()方法中,执行processWorkerExit(w, completedAbruptly);
终止线程