满足以上条件其中之一,就将workerCount减1并返回null,也就是表示队列中不再有任务。因为线程池的状态值是SHUTDOWN以上时,队列中不再允许添加新任务,所以上面两个条件满足一个都说明队列中的任务都取完了。
2、进入第二个if判断,这里的逻辑有点绕,但作用比较重要,是为了控制线程池的有效线程数量,我们来具体解析下代码:
wc > maximumPoolSize:判断当前线程数是否大于maximumPoolSize,这种情况一般很少发生,除非是maximumPoolSize的大小在该程序执行的同时被进行设置,比如调用ThreadPoolExecutor中的setMaximumPoolSize方法。
timed && timedOut:如果为true,表示当前的操作需要进行超时判断,并且上次从队列获取任务已经超时。
wc > 1 || workQueue.isEmpty():如果工作线程大于1,或者阻塞队列是空的。
compareAndDecrementWorkerCount:比较并将线程池中的workerCount减1
在上文中,我们解析execute方法的逻辑时了解到,如果当前线程池的线程数量超过了corePoolSize且小于maximumPoolSize,并且workQueue已满时,仍然可以增加工作线程。
但调用getTask()取任务的过程中,如果超时没有获取到任务,也就是timedOut为true的情况,说明workQueue已经为空了,也就说明了当前线程池中不需要那么多线程来执行任务了,可以把多于corePoolSize数量的线程销毁掉,也就是不断的让任务被取出,让线程数量保持在corePoolSize即可,直到getTask方法返回null。
而当getTask方法返回null后,runWorker方法中就会因为取不到任务而执行processWorkerExit()方法。
processWorkerExit方法
processWorkerExit方法的作用主要是对worker对象的移除,下面是方法的源码:
private void processWorkerExit(Worker w, boolean completedAbruptly) { //是异常退出的话,执行程序将workerCount数量减1 if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted decrementWorkerCount(); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { completedTaskCount += w.completedTasks; // 从workers的集合中移除worker对象,也就表示着从线程池中移除了一个工作线程 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); } }至此,从executor方法开始的整个运行过程就完毕了,总结一下该流程:
执行executor --> 新建Worker对象,并实例化线程 --> 调用runWorker方法,通过getTask()获取任务,并执行run方法 --> getTask()方法中不断向队列取任务,并将workerCount数量减1,直至返回null --> 调用processWorkerExit清除worker对象。
用一张流程图表示如下所示 (图片来源于https://www.cnblogs.com/liuzhihu/p/8177371.html):
前面我们多次提到了workQueue,这是一个任务队列,用来存放等待执行的任务,它是BlockingQueue
SynchronousQueue:直接提交的队列。这个队列没有容量,当接收到任务的时候,会直接提交给线程处理,而不保留它。如果没有空闲的线程,就新建一个线程来处理这个任务!如果线程数量达到最大值,就会执行拒绝策略。所以,使用这个类型队列的时候,一般都是将maximumPoolSize一般指定成Integer.MAX_VALUE,避免容易被拒绝。
ArrayBlockingQueue:有界的任务队列。需要给定一个参数来限制队列的长度,接收到任务的时候,如果没有达到corePoolSize的值,则新建线程 (核心线程) 执行任务,如果达到了,则将任务放入等待队列。如果队列已满,则在总线程数不到maximumPoolSize的前提下新建线程执行任务,若大于maximumPoolSize,则执行拒绝策略。
LinkedBlockingQueue:无界的任务队列。该队列没有任务数量的限制,所以任务可以一直入队,知道耗尽系统资源。当接收任务,如果当前线程数小于corePoolSize,则新建线程处理任务;如果当前线程数等于corePoolSize,则进入队列等待。
任务拒绝策略当线程池的任务队列已满并且线程数目达到maximumPoolSize时,对于新加的任务一般会采取拒绝策略,通常有以下四种策略:
AbortPolicy:直接抛出异常,这是默认策略;
CallerRunsPolicy:用调用者所在的线程来执行任务;
DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
DiscardPolicy:直接丢弃任务;
线程池的关闭