想象一下,若是你如今恰好在 word 上寫需求文檔,電腦忽然重啓。等待開機完成,你可能會發現寫了一個小時文檔沒有保存,就這麼沒了。。。html
一個正在運行 Java 應用若是忽然將其中止,影響不止數據丟失,還會形成其餘影響。好比:java
因此在關閉服務以前,咱們須要先作好善後工做,好比保存數據,清理資源,下線服務,而後才退出應用。這種有計劃平滑的關閉應用相對直接中止應用,就顯得很是『優雅』。數據庫
ps: 仔細品味,優雅停機這個詞真好~
Java 語言提供一種 ShutdownHook(鉤子)進制,當 JVM 接受到系統的關閉通知以後,調用 ShutdownHook 內的方法,用以完成清理操做,從而平滑的退出應用。緩存
ShutdownHook代碼以下:併發
Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("關閉應用,釋放資源"); }));
Runtime.getRuntime().addShutdownHook(Thread)
須要傳入一個線程對象,後續動做將會在該異步線程內完成。除了主動關閉應用(使用 kill -15 指令),如下場景也將會觸發 ShutdownHook :框架
System#exit
方法Ctrl+C
(非後臺運行)目前不少開源框架都是基於這個機制實現優雅停機,好比 Dubbo,Spring 等。異步
ShutdownHook 代碼實現起來相對簡單,可是咱們仍是須要當心下面這些坑。ide
Runtime.getRuntime().addShutdownHook(Thread)
能夠被屢次調用idea
咱們能夠屢次調用 Runtime.getRuntime().addShutdownHook(Thread)
方法,從而增長多個。可是須要注意的是,多個 ShutdownHook 之間並沒有任何順序,Java 並不會按照加入順序執行,反而將會併發執行。spa
因此儘可能在一個 ShutdownHook 完成全部操做。
ShutdownHook 須要儘快執行結束
不要在 ShutdownHook 執行須要被阻塞代碼,如 I/0 讀寫,這樣就會致使應用短期不能被關閉。
Runtime.getRuntime().addShutdownHook(new Thread(() -> { while (true){ System.out.println("關閉應用,釋放資源"); } }));
上面代碼中,咱們使用 while(true)
模擬長時間阻塞這種極端狀況,關閉該應用時,應用將會一直阻塞在 while
代碼中,致使應用沒辦法被關閉。
除了阻塞以外,還須要當心其餘會讓線程阻塞的行爲,好比死鎖。
爲了不 ShutdownHook 線程被長時間阻塞,咱們能夠引入超時進制。若是等待必定時間以後,ShutdownHook 還未完成,由腳本直接調用 kill -9 強制退出或者 ShutdownHook 代碼中引入超時進制。
文章首發於studyidea.cn
歡迎關注個人公衆號:程序通事,得到平常乾貨推送。若是您對個人專題內容感興趣,也能夠關注個人博客: studyidea.cn