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

相关文章
相关标签/搜索