Runtime.addShutdownHook()(譯)

序言:html

每個Java程序均可覺得JVM增長一個關閉鉤子。JVM將在關閉以前執行關閉鉤子中的指令。java

 

問題:數據庫

一個程序可能須要在退出前執行一些指令。程序可能因爲下列緣由而退出:api

  • 全部的線程已經執行完畢服務器

  • 調用System.exit()併發

  • 用戶輸入Ctrl+Coracle

  • 系統級關閉或用戶註銷ide

 

適用場景:工具

  • 保存應用狀態,例如,當多數IDE退出時,它們將記憶最後的視圖有哪些。ui

  • 關閉某些數據庫鏈接。

  • 將應用關閉的消息發送給系統管理員。

 

解決方案:

關閉鉤子支持全部這些場景。應用能夠增長一個關閉鉤子,JVM將在應用退出時調用它。

 

抽象層次的概念:

將全部的指令(Java代碼)寫入一個線程的run()內,而且調用java.lang.Runtime.addShutdownHook(Thread t)。該方法將這個線程註冊爲JVM的關閉鉤子。在關閉JVM的時候,JVM將並行地運行這些鉤子(線程將在JVM關閉的時候啓動)。

 

代碼示例:

public class AddShutdownHookSample {

     public void attachShutDownHook() {

         Runtime.getRuntime().addShutdownHook(new Thread() {

              @Override

              public void run() {

                   System.out.println("Inside Add Shutdown Hook");

              }

         });

         System.out.println("Shut Down Hook Attached.");

     }

 

     public static void main(String[] args) {

         AddShutdownHookSample sample = new AddShutdownHookSample();

         sample.attachShutDownHook();

         System.out.println("Last instruction of Program....");

         System.exit(0);

     }

}

 

輸出:

Shut Down Hook Attached.

Last instruction of Program....

Inside Add Shutdown Hook

 

如今明白瞭如何使用addShutDownHook。若是須要能夠增長多個關閉鉤子,可是須要注意的是,鉤子是並行地運行,因此注意併發避免死鎖發生。

 

在應用中實現關閉鉤子:

  • 關閉鉤子的數量:關閉鉤子的數量沒有限制,若是須要能夠增長多個關閉鉤子。看看run()的修改版本:

public void attachShutDownHook() {

         for (int i = 0; i < 10; i++) {

              Runtime.getRuntime().addShutdownHook(new Thread() {

                   @Override

                   public void run() {

                       System.out.println("Inside Add Shutdown Hook : "

                                 + Thread.currentThread().getName());

                   }

              });

         }

     }

      如上,咱們增長了10個關閉鉤子。

  • 什麼時候增長關閉鉤子:任什麼時候候!!!在任何狀況下均可以增長一個關閉鉤子,只要在JVM關閉以前。若是試圖在JVM開始關閉後註冊一個關閉鉤子,將拋出一個帶有」Shutdown is progress」消息的IllegalStateException

  • 增長相同的鉤子:不能增長相同的鉤子。若是這樣作了,將拋出帶有」Hook previously registered」消息的IllegalArgumentException

  • 註銷鉤子:調用Runtime.removeShutdownShook(Thread hook)能夠註銷一個鉤子。

注意:大多數時候,使用匿名內部類來註冊關閉鉤子,既然咱們沒有持有這些類的可用引用,咱們也沒法使用要註銷鉤子的匿名內部類,由於咱們須要將它們傳遞給removeShutdownHook(Thread hook)

  • 注意併發:萬一不止一個關閉鉤子,它們將並行地運行,並容易引起線程問題,例如死鎖。Java Doc對該方法是這樣描述的: /**

  * A <i>shutdown hook</i> is simply an initialized but unstarted thread.

  * When the virtual machine begins its shutdown sequence it will start all

  * registered shutdown hooks in some unspecified order and let them run

  * concurrently. When all the hooks have finished it will then run all

  * uninvoked finalizers if finalization-on-exit has been enabled. Finally,

  * the virtual machine will halt. Note that daemon threads will continue to

  * run during the shutdown sequence, as will non-daemon threads if shutdown

  * was initiated by invoking the <tt>{@link  #exit exit}</tt> method.

  */

翻譯過來:

關閉鉤子只是一個已初始化但還沒有啓動的線程。虛擬機開始啓用其關閉序列時,它會以某種未指定的順序啓動全部已註冊的關閉鉤子,並讓它們同時運行。運行完全部的鉤子後,若是已啓用finalization-on-exit,那麼虛擬機接着會運行全部未調用的finalizers。最後,虛擬機會暫停。注意,關閉序列期間會繼續運行守護線程,若是經過調用exit方法來發起關閉序列,那麼也會繼續運行非守護線程。

  • 關閉鉤子的可靠性:JVM將在退出的時候盡最大努力來執行關閉鉤子,可是不保證必定會執行。例如,當在Linux中使用-kill命令時,或在Windows中終結進程時,因爲本地代碼被調用,JVM將當即退出或崩潰。

  • 注意鉤子的時間消耗:須要注意的重點之一是,關閉鉤子不該該花費過多時間。考慮這樣一個場景,當用戶從操做系統中註銷,操做系統花費很是有限的時間就正常退出了,所以在這樣樣的場景下JVM也應該儘快退出。

 

結論:

Runtime.addShutdownHook(Thread hook)是很是方便的工具,它提供從JVM中優雅退出的一個通用機制。尤爲是在相似服務器實現這樣的大型應用中。固然,應該當心使用。

 

參考:

http://download.oracle.com/javase/1.5.0/docs/guide/lang/hook-design.html

http://download.oracle.com/javase/6/docs/api/java/lang/Runtime.html#addShutdownHook(java.lang.Thread)

 

原文地址:http://hellotojavaworld.blogspot.com/2010/11/runtimeaddshutdownhook.html

相關文章
相關標籤/搜索