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