ThreadPoolExecutor(六)——线程池关闭之后
?上一篇主要從代碼角度介紹了線程池關閉相關的方法,包括各個方法之間的邏輯關系,調用關系和產生的效果。
這一篇更多從邏輯角度上來說一下線程池在shutdown之后,原來正常的處理流程有哪些變化,既是總結也是擴展。
shutdown操作之后,首先最重要的一點變化就是線程池狀態變成了SHUTDOWN。該狀態是開始關閉線程池之后,從RUNNING改變狀態經過的第一個狀態(還有一種情況是直接進STOP,調用shutdownNow的時候),有個圖畫的挺好,見博客Java 7之多線程線程池 - 線程池原理(2)
從入口開始看,在這個狀態變化之后,每個方法的處理流程和之前比發生了什么變化?
1.execute
public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))reject(command);}有以下幾種情況:
1.如果現在狀態不是RUNNING,說明要么正在SHUTDOWN要么已經SHUTDOWN完畢了,這時isRunning方法是false,會走到最后一個else if中,通過addWorker的狀態來執行相應操作。addWorker下一個段落會說。
2.如果現在是RUNNING操作,而且入隊列成功了,然后這里需要一個double check,重新檢測線程池的狀態,如果不是RUNNING,而且remove成功,直接reject任務。如果remove方法失敗,什么都不做(因為有其他的方法正在remove任務,比如shoutDownNow的drainQueue,purge,runWorker結束時的processWorkerExit)。
3.如果現在是RUNNING操作,如果offer失敗了,說明隊列滿了,也執行最后一個if else,調用addWorker,這時也可能開啟了SHUTDOWN操作。
2.addWorker
// Check if queue empty only if necessary.if (rs >= SHUTDOWN &&! (rs == SHUTDOWN &&firstTask == null &&! workQueue.isEmpty()))return false;先看這個會返回false的判斷,
1.STOP,TIDYING和TERMINATED這三種狀態都會直接返回false。
2.如果是SHUTDOWN,而且firstTask不是null,也返回false。
3.如果是SHUTDOWN,firstTask是null,而且任務隊列是空,返回false。
現在要看的是SHUTDOWN狀態,fistTask是null,任務隊列不是空的情況。
addWorker(null, X)這種傳參方式,除了初始化線程數的時候,只有processWorkerExit,execute的recheck發現wc個數為0,這兩種情況。
關于addWorker傳null的含義還有些迷惑,上一篇中也特意有一個段落說這個問題,以后再研究下看看有沒有新的理解和發現。
3.getTask
/*** Performs blocking or timed wait for a task, depending on* current configuration settings, or returns null if this worker* must exit because of any of:* 1. There are more than maximumPoolSize workers (due to* a call to setMaximumPoolSize).* 2. The pool is stopped.* 3. The pool is shutdown and the queue is empty.* 4. This worker timed out waiting for a task, and timed-out* workers are subject to termination (that is,* {@code allowCoreThreadTimeOut || workerCount > corePoolSize})* both before and after the timed wait.** @return task, or null if the worker must exit, in which case* workerCount is decremented*/private Runnable getTask() {boolean timedOut = false; // Did the last poll() time out?retry: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;}boolean timed; // Are workers subject to culling?for (;;) {int wc = workerCountOf(c);timed = allowCoreThreadTimeOut || wc > corePoolSize;if (wc <= maximumPoolSize && ! (timedOut && timed))break;if (compareAndDecrementWorkerCount(c))return null;c = ctl.get(); // Re-read ctlif (runStateOf(c) != rs)continue retry;// else CAS failed due to workerCount change; retry inner loop}try {Runnable r = timed ?workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :workQueue.take();if (r != null)return r;timedOut = true;} catch (InterruptedException retry) {timedOut = false;}}}先看注釋:
在取任務的時候有兩種策略,一直阻塞或帶超時的等待,取決于線程池的參數設置。返回null如果該Worker由于以下幾種情況退出:
1.wc的數量超過了maximumPoolSize了(通常由于)調用了setMaximumPoolSize方法臨時減小了maximumPoolSize值,這時返回null來干掉Worker。
2.線程池處于STOP狀態。
3.線程池處于SHUTDOWN狀態,而且任務隊列是空的。
4.Worker在等待任務的時候超時了,而且超時的Worker需要被terminated,條件是allowCoreThreadTimeOut || workerCount > corePoolSize,即當該線程池允許核心線程timeout(無論是max還是core的Worker都會退出)或者當前wc個數已經超過了核心線程數的時候(退出的max線程的Worker),Worker可以退出線程池。
?
4.runWorker
runWorker中調用了getTask方法,所以其相應執行結果和getTask的返回有關。比如上一個段落中說的那幾種情況,線程池在SHUTDOWN狀態且任務隊列為空,會返回null。線程池在STOP狀態也會返回null(不檢查隊列是否為空,因為STOP狀態是shutdownNow引起的,所有task都已經被drainQueue方法移除了)。
而返回null意味著runWorker中的循環會結束,然后調用processWorkerExit方法去做一些Worker退出的相關操作。
總結
以上是生活随笔為你收集整理的ThreadPoolExecutor(六)——线程池关闭之后的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 传美团支付无证经营被央行叫停 限期三个月
- 下一篇: 07-小蜜蜂单片机中断系统