一、如何優雅關閉線程池
核心API:
- shutDown
- shutDownNow
- awaitTermination
利用JVM鈎子函數,在虛擬機關閉時調用相關方法即”優雅關閉線程池”。
先通過shutdown等待線程池自身結束,然后等待一段時間,如果沒有成功,再調用shutdownNow將等待I/O的任務中斷並退出。
/**
* 添加鈎子函數
*/
private void initGracefullyShutDown() {
Runtime.getRuntime().addShutdownHook(new Thread(() -> shutDownThreadPool(asyncExecutor, "BASE")));
aliasExecutors.forEach((alias, threadPoolExecutor) ->
Runtime.getRuntime().addShutdownHook(new Thread(() -> shutDownThreadPool(threadPoolExecutor, alias)))
);
}
/**
* 優雅關閉線程池。
* 自身關閉,await 60s,強制關閉。
*/
private void shutDownThreadPool(ExecutorService threadPool, String alias) {
log.info("Start to shutdown the thead pool : {}", alias);
threadPool.shutdown();
try {
if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
threadPool.shutdownNow();
log.warn("Interrupt the worker, which may cause some task inconsistent");
if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
log.warn("Thread pool can't be shutdown even with interrupting worker threads, which may cause some task inconsistent.");
}
}
} catch (InterruptedException ie) {
threadPool.shutdownNow();
log.warn("The current server thread is interrupted when it is trying to stop the worker threads. This may leave an inconsistent state.");
Thread.currentThread().interrupt();
}
}
備注:本來是循環調用shutDownThreadPool()方法, 后來發現阻塞嚴重,追了下源碼修改成了循環添加鈎子了,具體看如下。
二、其他
JVM鈎子函數
執行時機
自身沒有細追源碼,簡單看了幾篇其他伙伴記錄的博客。
- 虛擬機退出 :JVM會在所有非守護(后台)線程關閉后才會退出 (關於守護線程,隨便看了幾篇博客回憶下,這篇還不錯。《大白話講解守護線程》)
- 系統調用System.exit(0)
- JVM正常退出(Linux上kill命令也會調用鈎子函數)
追了一下源碼,看了下,發現是一個集合維護Threads。(即咱們調用API,add進去的)
ApplicationShutdownHooks.java
/* Iterates over all application hooks creating a new thread for each
* to run in. Hooks are run concurrently and this method waits for
* them to finish.
*/
static void runHooks() {
Collection<Thread> threads;
synchronized(ApplicationShutdownHooks.class) {
threads = hooks.keySet();
hooks = null;
}
for (Thread hook : threads) {
hook.start();
}
for (Thread hook : threads) {
while (true) {
try {
hook.join();
break;
} catch (InterruptedException ignored) {
}
}
}
}
}
參考 《可伸縮服務架構 框架與中間件》
參考 JVM的鈎子函數實踐調用