• Runtime.addShutdownHook()(译)


    序言:

    每一个Java程序都可以为JVM增加一个关闭钩子。JVM将在关闭之前执行关闭钩子中的指令。

    问题:

    一个程序可能需要在退出前执行一些指令。程序可能由于下列原因而退出:

    • 所有的线程已经执行完毕

    • 调用System.exit()

    • 用户输入Ctrl+C

    • 系统级关闭或用户注销

    适用场景:

    • 保存应用状态,例如,当多数IDE退出时,它们将记忆最后的视图有哪些。

    • 关闭某些数据库连接。

    • 将应用关闭的消息发送给系统管理员。

    解决方案:

    关闭钩子支持所有这些场景。应用可以增加一个关闭钩子,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

  • 相关阅读:
    PythonIDE
    Python学习笔记六:return的用法
    Python学习笔记三:逻辑操作符
    Python编程实现对CodeSys中ST代码的自动排版(一)
    Python学习笔记十二:列表(4)len 、in、For的使用
    Python学习笔记七:字符串的操作(一)
    Python学习笔记五:while语句
    Python编程实现对CodeSys中ST代码的自动排版(二)
    Python学习笔记十:列表(2)列表元素的读写
    Python学习笔记九:列表(1)列表元素介绍及创建方法
  • 原文地址:https://www.cnblogs.com/felixzh/p/11841741.html
Copyright © 2020-2023  润新知