zoukankan      html  css  js  c++  java
  • JVM进程的优雅关闭

    一、前言

    JVM的关闭方式可以分为三种:
    1. 正常关闭:当最后一个非守护线程结束、或者调用了System.exit、或者通过其他特定平台的方法关闭(发送SIGINT,SIGTERM信号等)
    2. 强制关闭:通过调用Runtime.halt方法、或者是在操作系统中直接kill(发送SIGKILL信号)掉JVM进程
    3. 异常关闭:运行中遇到RuntimeException异常、OOM错误等。

    请尊重作者劳动成果,转载请标明原文链接(原文持续更新,建议阅读原文):https://www.cnblogs.com/waterystone/p/12884761.html

    二、ShutdownHook

    通常JVM可使用runtime.addShutdownHook()对退出信号做处理,它让我们在程序正常退出或者发生异常时能有机会做一些清场工作。
    关闭钩子其实可以看成是一个已经初始化了的但还没启动的线程,当JVM关闭时会并发无序地执行注册的所有关闭钩子
    Runtime.getRuntime().addShutdownHook(handleThread);    //handleThread是信号处理线程。
    ShutdownHook响应的信号如下:
    • -1:如果使用了nohup则不响应;
    • -2:如果使用了后台&则不响应;
    • -15:都响应。
     
     
    注意事项:
    • 不要使用kill -9来结束进程,这样ShutdownHook得不到执行;
    • ShutdownHook要尽量短。计算机在关机前,会给所有的进程发送一个SIGTERM信号,等若干秒后就直接发送SIGKILL了;
    • ShutdownHook要保证线程安全。如果多次发送信号,那么ShutdownHook被不同的线程多次执行;

    三、SignalHandler

    用户可以自定义SignalHander对特定信号进行处理。
     
    class DebugSignalHandler implements SignalHandler
    {
       public static void listenTo(String name) {
          Signal signal = new Signal(name);
          Signal.handle(signal, new DebugSignalHandler());
       }
     
       public void handle(Signal signal) {
          System.out.println("Signal: " + signal);
          if (signal.toString().trim().equals("SIGTERM")) {
             System.out.println("SIGTERM raised, terminating...");
             System.exit(1);
          }
       }
    }
     Java对每个信号都启动一个线程进行处理。注册TERM信号,就启动"SIGTERM handler" 线程。即便主线程被阻塞,信号依然可以得到处理。由于对信号的处理是多线程的,所以应保证信号处理实例SignalHandler应该是线程安全的。
     

    四、总结

    • ShutdownHook只响应1、2、15三种信号,而JVM一般用nohup...&的方式启动,所以会忽略1、2两种信号;
    • ShutdownHook触发时,多个钩子会并发无序执行。如果资源关闭上有先后依赖则会有问题;

    4.1 优雅关闭

    由于ShutdownHook的并发无序执行,所以我们在优雅关闭时不能直接kill -15。比如有残留请求的情况,如果部分资源已关闭,那么残留请求的执行会有异常。
     
    正确流程如下:
    1. kill -12:等待10s。用户自定义SignalHandler处理12信号,而且此时所有的资源都是正常状态。1)告知上游该服务已关闭,不要再发请求;2)处理残留的请求;3)其他需要正常关闭的操作。
    2. kill -15:等待10s。这时会并发无序执行注册的ShutdownHook,很有可能不需要10sJVM就退出了。
    3. kill -9:如果kill -15还没有终止JVM,则直接强制退出。
    这里的优雅就体现在第一步的10秒kill -12,在资源都正常的情况下给业务一些时间来正常关闭服务
     

    五、参考

  • 相关阅读:
    TCP之“3次握手,4次挥手”问题——实例分析
    TCP之“3次握手,4次挥手”问题
    IO
    select用法&原理详解(源码剖析)(转)
    select(),fd_set(),fd_isset()
    AF_INET与套接字SOCKET
    Socket 编程简介
    Spring 事务控制
    Spring-Profile详解
    Spring的常用使用场景
  • 原文地址:https://www.cnblogs.com/waterystone/p/12884761.html
Copyright © 2011-2022 走看看