你知道如何安全正確的關閉執行緒池嗎?

2022-02-14 21:04:24 字數 3208 閱讀 7110

純潔的微笑

我們知道應用停機時需要釋放資源,關閉連線,而對於一些定時任務或者網路請求服務會使用執行緒池,當應用停機時我們需要正確安全的關閉執行緒池,如果處理不當,可能造成資料丟失,業務請求結果不正確等問題。

關閉執行緒池我們可以選擇什麼都不做,jvm 關閉時自然的會清除執行緒池物件。當然這麼做,存在很大的弊端,執行緒池中正在執行執行的執行緒以及佇列中還未執行任務將會變得極不可控。所以我們需要想辦法控制到這些未執行的任務以及正在執行的執行緒。

執行緒池 api 提供兩個主動關閉的方法threadpoolexecutor#shutdownnowthreadpoolexecutor#shutdown,這兩個方法都可以用於關閉執行緒池,但是具體效果卻不太一樣。

在說執行緒池關閉方法之前,我們先了解執行緒池狀態。

執行緒池狀態關係圖如下:

執行緒池狀態.png

從上圖我們看到執行緒池總共存在 5 種狀態,分別為:

當我們執行threadpoolexecutor#shutdown方法將會使執行緒池狀態從running轉變為shutdown。而呼叫threadpoolexecutor#shutdownnow之後執行緒池狀態將會從running轉變為stop。從上面的圖上還可以看到,當執行緒池處於shutdown,我們還是可以繼續呼叫threadpoolexecutor#shutdownnow方法,將其狀態轉變為stop

上面我們知道執行緒池狀態,這裡先說說shutdown方法。shutdown方法原始碼比較簡單,能比較直觀理解其呼叫邏輯。

shutdown方法原始碼:

public void shutdown()  finally 

tryterminate();

}

shutdown方法首先加鎖,其次先檢查系統安裝狀態。接著就會將執行緒池狀態變為shutdown,在這之後執行緒池不再接受提交的新任務。此時如果還繼續往執行緒池提交任務,將會使用執行緒池拒絕策略響應,預設情況下將會使用threadpoolexecutor.abortpolicy,丟擲rejectedexecutionexception異常。

執行緒池構造引數需要指定coresize(核心執行緒池數量),maximumpoolsize(最大的執行緒池數量),keepalivetime(多餘空閒執行緒等待時間),unit(時間單位),workqueue(阻塞佇列)。

當呼叫執行緒池的execute方法,執行緒池工作流程如下:

如果此時執行緒池中線程數量小於coresize,將會新建執行緒執行提交的任務。

如果此時執行緒池執行緒數量已經大於coresize,將會直接把任務加入到佇列中。執行緒將會從工作佇列中獲取任務執行。

如果工作佇列已滿,將會繼續新建執行緒。

如果工作佇列已滿,且執行緒數等於maximumpoolsize,此時將會使用拒絕策略拒絕任務。

超過coresize數量那部分執行緒,如果空閒了keepalivetime,執行緒將會終止。

工作流程圖如下:

執行緒池執行流程圖.png

當執行緒池處於第二步時,執行緒將會使用workqueue#take獲取隊頭的任務,然後完成任務。如果工作佇列一直沒任務,由於隊列為阻塞佇列,workqueue#take將會阻塞執行緒。

threadpoolexecutor#shutdownnow原始碼如下:

public listshutdownnow()  finally 

tryterminate();

return tasks;

}

shutdownnow方法將會把執行緒池狀態設定為stop,然後中斷所有執行緒,最後取出工作佇列中所有未完成的任務返回給呼叫者。

對比shutdown方法,shutdownnow方法比較粗暴,直接中斷工作執行緒。不過這裡需要注意,中斷執行緒並不代表執行緒立刻結束。這裡需要執行緒主動配合執行緒中斷響應。

執行緒池shutdownshutdownnow方法都不會主動等待執行任務的結束,如果需要等到執行緒池任務執行結束,需要呼叫awaittermination主動等待任務呼叫結束。

呼叫方法如下:

threadpool.shutdown();

try

} catch (interruptedexception e)

如果執行緒池任務執行結束,awaittermination方法將會返回true,否則當等待時間超過指定時間後將會返回false

如果需要使用這種進製,建議在上面的基礎上增加一定重試次數。這個真的很重要!!!

回顧上面執行緒池狀態關係圖,我們可以知道處於shutdown的狀態下的執行緒池依舊可以呼叫shutdownnow。所以我們可以結合shutdownshutdownnowawaittermination,更加優雅關閉執行緒池。

threadpool.shutdown(); // disable new tasks from being submitted

// 設定最大重試次數

try

} catch (interruptedexception ie)

你知道如何安全正確的關閉執行緒池嗎?

純潔的微笑 我們知道應用停機時需要釋放資源,關閉連線,而對於一些定時任務或者網路請求服務會使用執行緒池,當應用停機時我們需要正確安全的關閉執行緒池,如果處理不當,可能造成資料丟失,業務請求結果不正確等問題。關閉執行緒池我們可以選擇什麼都不做,jvm 關閉時自然的會清除執行緒池物件。當然這麼做,存在很...

執行緒池 如何正確的關閉執行緒池

在呼叫這個關閉方法時,執行緒池會根據我們配置的拒絕策略來拒絕掉想要進來的執行緒,也就是說吧建立執行執行緒的入口給關閉掉了,直到執行緒池內的所有執行緒都執行完成。在呼叫這個方法完畢之後,並不代表這個執行緒池就真的都停掉了,只能說他不讓其他執行緒進來了,然後等到執行緒池內的執行緒執行完。shutdown...

正確關閉執行緒池

使用10個固定執行緒池建立100個任務 executorservice service executors.newfixedthreadpool 10 for int i 0 i 100 i threadpoolexecutor中關閉執行緒池的方法 shutdown 可以安全地關閉乙個執行緒池,呼叫...