巡山小妖007

个人站

欢迎来到我的个人博客~


java中的优雅关闭

优雅关闭项目

之前对java中的延迟任务进行了了解,但是对于实现延迟队列的一些方式(延迟队列,环形队列等),如果使用这些方式,在生产上,如果需要重启项目的话,那缓存中的数据如何进行保存,因此在网上搜罗了一些关于java优雅关闭的一些博客,即在ShutDownHook钩子函数中加入一些将延迟队列中的数据存储起来的方法

Linux的信号机制

kill命令可将指定的信号发送给相应的进程,linux中常见的信号如下:

1 SIGHUP 挂起进程

2 SIGINT 终止进程

3 SIGGQUIT 停止进程

9 SIGKILL 无条件终止进程

15 SIGTERM 尽可能终止进程

17 SIGSTOP 无条件停止进程,但不是终止

18 SIGTSTP 停止或者暂停进程,但不终止进程

19 SIGCONT 继续运行停止的进程

默认情况下kill命令使用的是kill -15,此时,如果java程序中定义的shutDownHook时,会触发; 如果使用kill -9则不会触发钩子


  • 1、ShutDownHook函数
/**
 * cmd执行javac 编译后  使用java执行class文件
 *   执行了 java TestShutDownHook  之后,输出“main executing”
 *   但按 Ctrl+c之后,会输出shutDownHook execute
 *   此时代表钩子函数执行了
 */
public class TestShutDownHook {

    public static void main(String[] args) {

        System.out.println("main executing");

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("shutDownHook execute");
        }));
        try {
            TimeUnit.DAYS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

以上代码在linux系统中执行 kill -15 test.jar 时,会回调ShutDownHook方法

  • 2、springboot中的ShutDownHook

springboot项目中可以在自定义Bean对象,在启动时,添加ShutDownHook

package com.xsxy.alltestproject.springbootShutDownHook;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
@Component
public class SpringbootShutDownHook {

    @PostConstruct
    public void registerShutDownHook(){
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("springboot execute shutdownhook");
        }));
    }

}

测试:

打出jar包后,使用java -jar test.jar 启动springboot项目

nohup java -jar all-test-project-0.0.1-SNAPSHOT.jar &

-->
[1] 6641

使用kill -15 终止进程,会将springboot execute shutdownhook日志输出到nohup文件中

而使用kill -9时,并不会调用ShutDownHook的方法


以下为网上的案例未经过测试:

  • 3、 实现SignalHandler
public class KillHandler implements SignalHandler {  
  
    public void registerSignal(String signalName) {  
        Signal signal = new Signal(signalName);  
        Signal.handle(signal, this);  
    }  
  
    @Override  
    public void handle(Signal signal) {  
         
        if (signal.getName().equals("TERM")) {  
                //  
        } else if (signal.getName().equals("INT") || signal.getName().equals("HUP")) {  
                //  
        } else {  
                //  
        }  
    }  
  
} 

​ 程序启动时实例化一个KillHandler,注册TERM信号。

​ KillHandler killHandler = new KillHandler();

​ killHandler.registerSignal(“TERM”);

​ 这样,在进程被kill的时候就会触发KillHandler的handle方法。

相关博客 https://blog.csdn.net/u011001084/article/details/73480432 https://blog.csdn.net/m0_37793798/article/details/84206167 https://blog.csdn.net/chinrui/article/details/78685032

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦