如何優雅地關閉線程池?
在 Java的線程池管理中,shutdown()和shutdownNow()是用于關閉線程池的兩種方法,盡管都是為了關閉線程池,但它們存在顯著差異。這篇文章,我們將詳細闡述它們的工作原理。

shutdown()
shutdown()的使用方式如下所示:
ExecutorService executor = Executors.newFixedThreadPool(3);
...
executor.shutdown();(1) shutdown()的工作原理:
- shutdown() 方法的主旨是指示線程池進入“關閉狀態”,即線程池不再接受新任務請求。
- 任何已經提交的任務,包括那些在等待執行隊列中的任務,會繼續執行,直到所有任務完成后線程池完全停止。
- 調用 shutdown() 后,線程池的狀態變為"SHUTDOWN",但不會中斷正在執行的任務。
通過 shutdown() 關閉線程池,所有正在處理的任務和已提交的任務庫將正常完成,不會有半途被終止的情況發生。
(2) shutdown()的特點:
- 平滑停止:調用后線程池會拒絕新任務,但不會強制停止已提交和正在運行的任務。從這種意義上來說,shutdown() 提供了一種平穩的關閉方式。
- 阻塞等待的任務會正常執行:那些已經正式提交但還沒被執行的任務仍在等待隊列中,可以繼續被線程池拾取和處理。
- 等待線程自行完成任務:只要所有任務完成后,線程池就會完全停止。
(3) shutdown()的 注意事項:
①shutdown() 不會立即終止線程池,而是等待所有已經提交的任務(包括正在執行的和在任務隊列中的)完成。
②如果你需要檢查線程池是否已關閉,可以使用如下方法:
- isShutdown():如果已經調用了 shutdown(),返回 true。
- isTerminated():如果線程池完全停止了,所有任務都已經完成或中止,返回 true。
通過 shutdown() 關閉的線程池不會突然地停止任務,這在一些長時間處理數據或大批量任務的場景中尤為重要。
shutdownNow()
shutdownNow()的用法如下代碼:
ExecutorService executor = Executors.newFixedThreadPool(3);
...
executor.shutdownNow();(1) shutdownNow()的工作原理:
- shutdownNow() 會立即嘗試停止所有正在執行的任務,并返回尚未執行的任務列表。
- 線程池會調用每個線程的 interrupt() 函數來嘗試停止它們。
- 和 shutdown() 不同,shutdownNow()是一個“強制式”的關閉方式。在調用后,線程池會試圖中斷當前所有正在執行的任務,并返回那些還沒來得及執行的任務。
(2) shutdownNow()的特點:
- 強制終止:shutdownNow() 不只是停止接收新任務,還會中斷當前正在執行的任務以及移除隊列中還未執行的任務。
- 返回未開始的任務:它會返回哪些任務沒有被執行,還在任務隊列里等待,而這些任務不再會被執行。
- 潛在的任務中斷:shutdownNow() 實際上通過 Thread.interrupt() 方法來嘗試終止正在執行的任務。因此,如果任務沒有處理好中斷操作(即不考慮線程的中斷狀態),某些正在執行的任務可能不會及時終止。
兩者對比
(1) 接收新任務
- shutdown():此方法調用后,線程池不再接受任何新的任務請求。任務隊列中已經被提交的任務會繼續執行。
- shutdownNow():此方法調用后,線程池立即拒絕新任務,同時會嘗試中斷當前運行中的任務。
(2) 執行已提交的任務
- shutdown():不再受理新的任務提交,已提交而尚未執行的任務會繼續執行直到正常完成。
- shutdownNow():會嘗試中斷正在運行的任務,并返回那些還未被執行的任務列表。
(3) 對線程的影響
- shutdown():等待所有線程完成,線程池逐漸關閉。
- shutdownNow():粗暴地嘗試中斷所有線程,線程可能會在處理中途中斷并無法完成任務。
(4) 線程中斷
- shutdown():不主動中斷任何線程。
- shutdownNow():主動中斷線程。
總結
本文我們分析了shutdown() 和 shutdownNow()的原理以及它們之間的差異,兩者都是用于關閉 Java的線程池,是一個比簡單的知識點,在實際工作中,我們一般很少主動去關閉線程池,但是如果工作中真的存在關閉線程池的需求,掌握兩個方法對我們會有很大的幫助。





























