- 我們經常在項目中使用的線程池,但是是否關心過線程池的關閉呢,可能很多時候直接再項目中直接創建線程池讓它一直運行當任務執行結束不在需要了也不去關閉,這其實是存在非常大的風險的,大量的線程常駐在后台對系統資源的占用是巨大的 ,甚至引發異常。所以在我們平時使用線程池時需要注意優雅的關閉,這樣可以保證資源的管控。
- 在
Java
中和關閉線程池相關的方法主要有如下:void shutdown()
List<Runnable> shutDownNow
boolean awaitTermination
boolean isShutDown
boolean isTerminated
- 對於這些方法有着不同的使用和作用,下面我們真的會這些不同的方法做詳細的介紹。
ShutDown
shutDown
方法從字面意思我們可以看到是停止關閉的意思,我們先來看下面的一段代碼,首先我們通過ThreadPoolExecutor
來創建一個容量是10的無界線程池,與FixedThreadPool
類似的,這里手動創建可以更好地理解線程池的創建。在后我們提交一千個任務執行,再執行shutdown
方法進行暫停。
public static void main(String[] args) throws InterruptedException {
ExecutorService service = new ThreadPoolExecutor(
10,
10,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>());
for (int i = 0; i < 1000; i++) {
service.submit(() ->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("接受中斷,不處理~~");
}
System.out.println("args = " + Arrays.deepToString(args)+ Thread.currentThread().getName());
});
}
service.shutdown();
}
- 我們可以看到結果所以線程會正常執行結束后再關閉線程池,對於
ShutDown
而言它可以安全的停止一個線程池,它有幾個關鍵點 ShutDown
會首先將線程設置成SHUTDOWN
狀態,然后中斷所有沒有正在運行的線程- 正在執行的線程和已經在隊列中的線程並不會被中斷,說白了就是使用
shutDown
方法其實就是要等待所有任務正常全部結束以后才會關閉線程池 - 調用
shutdown()
方法后如果還有新的任務被提交,線程池則會根據拒絕策略直接拒絕后續新提交的任務。
ShutDownNow
- 這個方法與上面方法相比較,直觀就是
now
,即立即停止任務, - 同樣是上述案列,略作修改如下,
public static void main(String[] args) throws InterruptedException {
ExecutorService service = new ThreadPoolExecutor(
10,
10,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1000));
for (int i = 0; i < 1000; i++) {
service.submit(() ->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("接受中斷,結束線程~~");
//這里響應中斷
return;
}
System.out.println("args = " + Arrays.deepToString(args)+ Thread.currentThread().getName());
});
}
final List<Runnable> runnables = service.shutdownNow();
System.out.println(runnables);
}
- 執行上述代碼我們發現,當執行
shutDownNow
方法后,會像全部正在運行的隊列通知中斷,正在運行的線程接收到中斷信號后選擇處理,而在隊列中的全部取消執行轉移到一個list
隊列中返回,如上述List<Runnable> runnables
,這里記錄了所有終止的線程
awaitTermination
- 這個方法並不是用來關閉線程池的,首先我們看一下這個方法的定義:
boolean awaitTermination_(long timeout, TimeUnit unit)_
- 可以看到這個方法有兩個參數,
timeout
表示等待的時間,unit
時間單位 - 這個方法的作用是,調用后等待
timeout
時間后,反饋線程池的狀態, - 等待期間(包括進入等待狀態之前)線程池已關閉並且所有已提交的任務(包括正在執行的和隊列中等待的)都執行完畢,相當於線程池已經“終結”了,方法便會返回
true
; - 等待超時時間到后,第一種線程池“終結”的情況始終未發生,方法返回
false
; - 等待期間線程被中斷,方法會拋出 InterruptedException 異常。
- 上面代碼可以修改來測試,這里不再粘貼代碼
isShutDown
isShutDown
方法正如名字,判斷線程池是否停止,返回的是Boolean
類型,如果已經開始停止線程池則返回true
否則放回false- 當調用了
shutDown
或shutDownNow
時之后,會返回true
不過需要注意,這時候只是代表線程池關閉流程的開始,並不是說線程池已經停止了
isTerminated
- 這個方法與上面的方法的區別就是這是正真檢測線程池是否真的終結了
- 這不僅代表線程池已關閉,同時代表線程池中的所有任務都已經都執行完畢了,因為在調用
shutdown
方法之后,線程池會繼續執行里面未完成的任務,包括正在執行的任務和在任務隊列中等待的任務。 - 如果調用了
shutdown
方法,但是有一個線程依然在執行任務,那么此時調用isShutdown
方法返回的是true
,而調用isTerminated
方法返回的便是false
,因為線程池中還有任務正在在被執行,線程池並沒有真正“終結”。 - 直到所有任務都執行完畢了,調用
isTerminated()
方法才會返回true
,這表示線程池已關閉並且線程池內部是空的,所有剩余的任務都執行完畢了。
本文由AnonyStar 發布,可轉載但需聲明原文出處。
歡迎關注微信公賬號 :雲棲簡碼 獲取更多優質文章
更多文章關注筆者博客 :雲棲簡碼 i-code.online