91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

ShutdownHook如何讓應用優雅的停止

發布時間:2022-01-04 18:10:26 來源:億速云 閱讀:178 作者:柒染 欄目:大數據

今天就跟大家聊聊有關ShutdownHook如何讓應用優雅的停止,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

對于應用,停止的時候一般都會把環境和數據恢復到運行前的樣子,和單元測試時tearDown要做的效果基本類似。而為了實現停止時恢復現場,英文中有個特定的描述:

shutdown gracefully

在Java中,為了實現gracefully shutdown,有一個特定的接口可供使用,就是我們今天要提到的shutdown hook。它與回調函數功能類似,文檔中對其描述如下:

關閉鉤子 只是一個已初始化但尚未啟動的線程。虛擬機開始啟用其關閉序列時,它會以某種未指定的順序啟動所有已注冊的關閉鉤子,并讓它們同時運行。運行完所有的鉤子后,如果已啟用退出終結,那么虛擬機接著會運行所有未調用的終結方法。最后,虛擬機會暫停。注意,關閉序列期間會繼續運行守護線程,如果通過調用 exit 方法來發起關閉序列,那么也會繼續運行非守護線程。

要為應用添加shutdownHook,需要做的只是這樣的下操作:

Runtime.getRuntime().addShutdownHook(new Thread() {
 
    public void run() { /*
       my shutdown code here
    */ }
 });

向addShutdownHook方法傳入的Thread,其run方法即為自定義的shutdown時清理邏輯。

JDK內部,是通過一個Map來保存所有添加的ShutdownHook,在被觸發時執行。

public void addShutdownHook(Thread hook) {
   SecurityManager sm = System.getSecurityManager();
   if (sm != null) {
       sm.checkPermission(new RuntimePermission("shutdownHooks"));
   }
   ApplicationShutdownHooks.add(hook);
 

 
static synchronized void add(Thread hook) {
    hooks.put(hook, hook);
}
 

 
private static IdentityHashMap<Thread, Thread> hooks;
 
hooks = new IdentityHashMap<>();

那這個shutdownHook一般是在什么時候會被調用呢?

我們看JDK的文檔中描述,對于兩類事件Java虛擬機會退出:

Java 虛擬機會為了響應以下兩類事件而關閉

  • 程序正常退出,這發生在最后的非守護線程退出時,或者在調用 exit(等同于 System.exit)方法時。或者,

  • 為響應用戶中斷而終止 虛擬機,如鍵入 ^C;或發生系統事件,比如用戶注銷或系統關閉。 

在Java虛擬機退出的時候,這些設置的shutdownHook會被并行的調用。但需要注意的是,對于非正常方式退出Java虛擬機,例如殺進程,系統斷電等,這些情況下,shutdownHook不會被執行。

我們來看,在Tomcat內部,是如何使用ShutdownHook的。

Catalina類內部,在服務器內部各個組件啟動完畢后,有這樣一段代碼


 
// Register shutdown hook
if (useShutdownHook) {
   if (shutdownHook == null) {
       shutdownHook = new CatalinaShutdownHook();
   }
   Runtime.getRuntime().addShutdownHook(shutdownHook);
 
}

和我們在本文開頭看到的一樣,他注冊了一個ShutdownHook。這個hook的內容如下:


 
/**
* Shutdown hook which will perform a clean shutdown of Catalina if needed.
*/
protected class CatalinaShutdownHook extends Thread {
   public void run() {
       try {
           if (getServer() != null) {
               Catalina.this.stop();
           }
       } catch (Throwable ex) {
       } finally {
       }
   }
}

看就是在shutdown的時候通過調用應用服務器的stop方法,來shutdown gracefully。

而我們一般停止Tomcat會通過調用shutdown腳本的方式進行,這個時候,腳本實質上去執行了應用服務器的stop方法來進行停止,而不是被shutdownHook來反調過來的。

因此,在讀源碼時,你會發現代碼中有這樣的內容:

/**
* Stop an existing server instance.
*/
public void stop() {

   try {
       // Remove the ShutdownHook first so that server.stop()
       // doesn't get invoked twice
       if (useShutdownHook) {
        Runtime.getRuntime().removeShutdownHook(shutdownHook);  
   } catch (Throwable t) {
       ExceptionUtils.handleThrowable(t);}

我們看到,在停止Server的時候,會先執行removeShutdownHook的操作,注釋里寫的明白,是為了防止server和stop被執行兩次。

哪種情況下會被執行兩次呢?

當使用catalina的shutdown腳本停止Server時,這個方法并不是從shutdownHook調用過來,此時,shutdownHook還沒有執行,所以在JVM退出的時候,shutdownHook會被觸發。如果此處還沒去remove掉的話,就還會調用過來。這一點在我們自己開發應用時需要注意借鑒一下。

看到這里,希望你不要說然并卵。

當然,如果你已經脫口而出,那...

我找了例子證明,你已經在不知不覺中使用了shutdownHook,例如你在輸出日志的時候,以下代碼是JDK的LogManager中的一部分,我們看到,其構造方法中直接會添加一個名為Cleaner的shutdownHook。

private LogManager(Void checked) {
   // Add a shutdown hook to close the global handlers.
   try {
       Runtime.getRuntime().addShutdownHook(new Cleaner());
   } catch (IllegalStateException e) {
       // If the VM is already shutting down,
       // We do not need to register shutdownHook.
   }
}
 

public void run() {

// This is to ensure the LogManager.<clinit> is completed
   // before synchronized block. Otherwise deadlocks are possible.
   LogManager mgr = manager;
   // Do a reset to close all active handlers.
   reset();
}

我們自己添加shutdownHook的時候,需要注意的是:

在內部不要寫耗時的操作,也不要寫容易引起死鎖的操作。多個ShutdownHook之間如果存在資源競爭而死鎖,那應用就停止不了了。

看完上述內容,你們對ShutdownHook如何讓應用優雅的停止有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

开封市| 抚州市| 博乐市| 营口市| 田东县| 司法| 阳西县| 琼中| 商洛市| 逊克县| 阳城县| 循化| 黎城县| 尚义县| 东兰县| 万盛区| 武宁县| 凤庆县| 宁德市| 屯昌县| 修武县| 普宁市| 海晏县| 平陆县| 阿坝| 军事| 疏勒县| 濉溪县| 德安县| 郧西县| 胶南市| 商水县| 崇左市| 广水市| 敖汉旗| 上蔡县| 郸城县| 常州市| 兰州市| 开阳县| 徐汇区|