• Tags
  •         
  • www.breakyizhan.com
  •    

    Shutdown Hooks是一种特殊的结构,允许开发人员插入一段代码,以便在JVM关闭时执行。如果我们需要在VM关闭的情况下进行特殊的清理操作,这就派上用场了。

    使用常规构造处理此问题,例如确保在应用程序存在之前调用特殊过程(调用System.exit(0))将不适用于VM因外部原因而关闭的情况(例如kill请求)来自O / S),或者由于资源问题(内存不足)。正如我们将很快看到的那样,关闭钩子可以通过允许我们提供任意代码块来轻松解决这个问题,JVM在关闭时会调用它。

    从表面看,使用Shutdown Hooks是直接向前的。我们所要做的就是编写一个扩展java.lang.Thread类的类,并在public void run()方法中提供我们想要在VM关闭时执行的逻辑。然后我们通过调用Runtime.getRuntime()。addShutdownHook(Thread)方法将此类的实例注册为VM的关闭挂钩。如果需要删除以前注册的关闭挂钩,Runtime类也会提供removeShutdownHook(Thread)方法。

    例如 :

    public class ShutDownHook
    {
      public static void main(String[] args)
      {
    
        Runtime.getRuntime().addShutdownHook(new Thread()
        {
          public void run()
          {
            System.out.println("Shutdown Hook is running !");
          }
        });
        System.out.println("Application Terminating ...");
      }
    }
    

    当我们运行上面的代码时,您将看到JVM在完成main方法的执行时调用了shutdown钩子。

    输出:

    Application Terminating ...
    Shutdown Hook is running !

    简单吧?是的。

    虽然编写一个关闭钩子非常简单,但是需要知道关闭钩子后面的内部才能正确使用它们。因此,在本文中,我们将探讨关闭钩子设计背后的一些“陷阱”。

    1.在某些情况下可能无法执行关机挂钩!
    首先要记住的是,无法保证关闭挂钩始终会运行。如果JVM由于某些内部错误而崩溃,那么它可能会在没有机会执行单个指令的情况下崩溃。此外,如果O / S给出SIGKILL(http://en.wikipedia.org/wiki/SIGKILL)信号(Unix / Linux中的kill -9)或TerminateProcess(Windows),则应用程序需要立即终止甚至等待任何清理活动。除了上述内容之外,还可以通过调用Runime.halt()方法来终止JVM而不允许关闭挂钩运行。

    当应用程序正常终止时(当所有线程完成或调用System.exit(0)时),将调用关闭挂钩。此外,当JVM由于外部原因(例如用户请求终止(Ctrl + C)),由O / S(正常kill命令,不带-9)或操作系统关闭时发出SIGTERM而关闭时。

    2.一旦启动,可在完成前强行停止关机钩。
    这实际上是前面解释过的案例的一个特例。虽然钩子开始执行,但在操作系统关闭的情况下,可以在它完成之前终止。在这种情况下,一旦给出SIGTERM,O / S就等待进程终止指定的时间。如果进程未在此时间限制内终止,则O / S通过发出SIGTERM(或Windows中的对应方)强制终止进程。因此,当关闭钩子执行到一半时,可能会发生这种情况。

    因此,建议确保快速写入关机挂钩,确保它们快速完成,并且不会导致死锁等情况。此外,JavaDoc [1]特别提到不应该执行长计算或在关闭钩子中等待用户I / O操作。

    3.我们可以有多个关机挂钩,但不保证执行顺序。
    正如您可能已经通过addShutdownHook方法的方法名称(而不是setShutdownHook)正确猜到的那样,您可以注册多个关闭挂钩。但是JVM无法保证这些多个钩子的执行顺序。JVM可以以任意顺序执行关闭挂钩。此外,JVM可以同时执行所有这些挂钩。

    4.我们无法在关闭挂钩中注册/取消注册关闭挂钩
    一旦JVM启动关闭序列,就不允许添加更多或删除任何现有的关闭挂钩。如果尝试这样做,JVM将抛出IllegalStateException。

    5.一旦关闭序列启动,它只能由Runtime.halt()停止。
    一旦关闭序列启动,只有Runtime.halt()(强制终止JVM)才能停止执行关闭序列(除了SIGKILL等外部影响)。这意味着在Shutdown Hook中调用System.exit()将不起作用。实际上,如果你在Shutdown Hook中调用System.exit(),VM可能会卡住,我们可能不得不强行终止进程。

    6.使用shutdown hooks需要安全权限。
    如果我们使用Java安全管理器,则执行添加/删除关闭挂钩的代码需要在运行时具有shutdownHooks权限。如果我们在安全环境中未经许可调用此方法,则会导致SecurityException。

     
    转载请保留页面地址:https://www.breakyizhan.com/java/4981.html