《Java線程池》:Executor生命週期
我們知道線程是有多種執行狀態的,同樣管理線程的線程池也有多種狀態。JVM會在所有線程(非後台daemon線程)全部終止後才退出,為了節省資源和有效釋放資源關閉一個線程池就顯得很重要。有時候無法正確的關閉線程池,將會阻止JVM的結束。
線程池Executor是非同步執行任務,因此任何時刻不能夠直接擷取提交的任務的狀態。這些任務有可能已經完成,也有可能正在執行或者還在排隊等待執行。因此關閉線程池可能出現一下幾種情況:
1、平緩關閉:已經啟動的任務全部執行完畢,同時不再接受新的任務
2、立即關閉:取消所有正在執行和未執行的任務
另外關閉線程池後對於任務的狀態應該有相應的反饋資訊。
圖1 描述了線程池的4種狀態。
1、線程池在構造前(new操作)是初始狀態,一旦構造完成線程池就進入了執行狀態RUNNING。嚴格意義上講線程池構造完成後並沒有線程被立即啟動,只有進行“開機前”或者接收到任務的時候才會啟動線程。這個會後麵線程池的原理會詳細分析。但是線程池是出於運行狀態,隨時準備接受任務來執行。
2、線程池運行中可以通過shutdown()和shutdownNow()來改變運行狀態。shutdown()是一個平緩的關閉過程,線程池停止接受新的任務,同時等待已經提交的任務執行完畢,包括那些進入隊列還沒有開始的任務,這時候線程池處於SHUTDOWN狀態;shutdownNow()是一個立即關閉過程,線程池停止接受新的任務,同時線程池取消所有執行的任務和已經進入隊列但是還沒有執行的任務,這時候線程池處於STOP狀態。
3、一旦shutdown()或者shutdownNow()執行完畢,線程池就進入TERMINATED狀態,此時線程池就結束了。
isTerminating()描述的是SHUTDOWN和STOP兩種狀態。
isShutdown()描述的是非RUNNING狀態,也就是SHUTDOWN/STOP/TERMINATED三種狀態。
線程池的API如下:
其中shutdownNow()會返回那些已經進入了隊列但是還沒有執行的工作清單。awaitTermination描述的是等待線程池關閉的時間,如果等待時間軸程池還沒有關閉將會拋出一個逾時異常。
對於關閉線程池期間發生的任務提交情況就會觸發一個拒絕執行的操作。這是java.util.concurrent.RejectedExecutionHandler描述的任務操作。下一個小結中將描述這些任務被拒絕後的操作。
總結下這個小節:
1、線程池有運行、關閉、停止、結束四種狀態,結束後就會釋放所有資源
2、平緩關閉線程池使用shutdown()
3、立即關閉線程池使用shutdownNow(),同時得到未執行的工作清單
4、檢測線程池是否正處於關閉中,使用isShutdown()
5、檢測線程池是否已經關閉使用isTerminated()
6、定時或者永久等待線程池關閉結束使用awaitTermination()操作
上面關於線程池生命週期的內容來自於部落格:http://www.blogjava.net/xylz/archive/2011/01/04/342316.html。
上面確實講解的比較清晰了,但是,自己在看ThreadPoolExecutor類的源碼過程中,發現,線程池的生命週期不只有:RUNNING、SHUTDOWN、STOP/TERMINATED四種狀態,還有一個TIDYING狀態。
在ThreadPoolExecutor類源碼中截取內容如下:
* The runState provides the main lifecycle control, taking on values: * * RUNNING: Accept new tasks and process queued tasks * SHUTDOWN: Don't accept new tasks, but process queued tasks * STOP: Don't accept new tasks, don't process queued tasks, * and interrupt in-progress tasks * TIDYING: All tasks have terminated, workerCount is zero, * the thread transitioning to state TIDYING * will run the terminated() hook method * TERMINATED: terminated() has completed * * The numerical order among these values matters, to allow * ordered comparisons. The runState monotonically increases over * time, but need not hit each state. The transitions are: * * RUNNING -> SHUTDOWN * On invocation of shutdown(), perhaps implicitly in finalize() * (RUNNING or SHUTDOWN) -> STOP * On invocation of shutdownNow() * SHUTDOWN -> TIDYING * When both queue and pool are empty * STOP -> TIDYING * When pool is empty * TIDYING -> TERMINATED * When the terminated() hook method has completed * * Threads waiting in awaitTermination() will return when the * state reaches TERMINATED. * * Detecting the transition from SHUTDOWN to TIDYING is less * straightforward than you'd like because the queue may become * empty after non-empty and vice versa during SHUTDOWN state, but * we can only terminate if, after seeing that it is empty, we see * that workerCount is 0 (which sometimes entails a recheck -- see * below).
上面的英文比較簡單,也比較好理解,這裡就不翻譯的,根據上面的意思,也就是說,線程池在SHUTDOWM/STOP到TERMINATED狀態之間還存在一個TIDYING狀態。這幾個狀態的變化是這樣的,這裡載貼一下,有興趣的也可以去源碼中看一看。
* RUNNING -> SHUTDOWN * On invocation of shutdown(), perhaps implicitly in finalize() * (RUNNING or SHUTDOWN) -> STOP * On invocation of shutdownNow() * SHUTDOWN -> TIDYING * When both queue and pool are empty * STOP -> TIDYING * When pool is empty * TIDYING -> TERMINATED * When the terminated() hook method has completed
小結
本節我們需要瞭解的就是線程池的生命週期,回顧下,線程池的狀態有:
1、RUNNING
2、SHUNDOWN
3、STOP
4、TIDYING
5、TERMINATED
這幾個狀態的轉化關係為:
1、調用shundown()方法線程池的狀態由RUNNING——>SHUTDOWN
2、調用shutdowNow()方法線程池的狀態由RUNNING——>STOP
3、當任務隊列和線程池均為空白的時候 線程池的狀態由STOP/SHUTDOWN——–>TIDYING
4、當terminated()方法被調用完成之後,線程池的狀態由TIDYING———->TERMINATED狀態 參考資料
部落格:http://www.blogjava.net/xylz/archive/2011/01/04/342316.html。