ShutdownHook - Java 優雅停機解決方案

想象一下,若是你如今恰好在 word 上寫需求文檔,電腦忽然重啓。等待開機完成,你可能會發現寫了一個小時文檔沒有保存,就這麼沒了。。。html

一個正在運行 Java 應用若是忽然將其中止,影響不止數據丟失,還會形成其餘影響。好比:java

  • 請求丟失:內存隊列中等待執行請求丟失
  • 數據丟失:處於內存緩存中數據未持久化到磁盤
  • 文件損壞:正在寫的文件沒有沒有更新完成,致使文件損壞
  • 業務中斷:處理一半的業務被強行中斷,如支付成功了,卻沒有更新到數據庫中
  • 服務未下線:上游服務依然往中止節點發送請求

因此在關閉服務以前,咱們須要先作好善後工做,好比保存數據,清理資源,下線服務,而後才退出應用。這種有計劃平滑的關閉應用相對直接中止應用,就顯得很是『優雅』。數據庫

ps: 仔細品味,優雅停機這個詞真好~

ShutdownHook

Java 語言提供一種 ShutdownHook(鉤子)進制,當 JVM 接受到系統的關閉通知以後,調用 ShutdownHook 內的方法,用以完成清理操做,從而平滑的退出應用。緩存

ShutdownHook代碼以下:併發

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("關閉應用,釋放資源");
        }));

Runtime.getRuntime().addShutdownHook(Thread) 須要傳入一個線程對象,後續動做將會在該異步線程內完成。除了主動關閉應用(使用 kill -15 指令),如下場景也將會觸發 ShutdownHook :框架

  • 代碼執行結束,JVM 正常退出
  • 應用代碼中調用 System#exit 方法
  • 應用中發生 OOM 錯誤,致使 JVM 關閉
  • 終端中使用 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

其餘平臺.png

相關文章
相關標籤/搜索