而这种自定义JVM清理动作的方式,是通过JDK中提供的shutdown hook实现的。JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子。
例子如下:
package com.hollis; public class ShutdownHookTest { public static void main(String[] args) { boolean flag = true; Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("hook execute..."); })); while (flag) { // app is runing } System.out.println("main thread execute end..."); } }执行命令:
➜ jps 6520 ShutdownHookTest 6521 Jps ➜ kill 6520控制台输出内容:
hook execute... Process finished with exit code 143 (interrupted by signal 15: SIGTERM)可以看到,当我们使用kill(默认kill -15)关闭进程的时候,程序会先执行我注册的shutdownHook,然后再退出,并且会给出一个提示:interrupted by signal 15: SIGTERM
如果我们执行命令kill -9:
➜ kill -9 6520控制台输出内容:
Process finished with exit code 137 (interrupted by signal 9: SIGKILL)可以看到,当我们使用kill -9 强制关闭进程的时候,程序并没有执行shutdownHook,而是直接退出了,并且会给出一个提示:interrupted by signal 9: SIGKILL
总结kill命令用于终止Linux进程,默认情况下,如果不指定信号,kill 等价于kill -15。
kill -15执行时,系统向对应的程序发送SIGTERM(15)信号,该信号是可以被执行、阻塞和忽略的,所以应用程序接收到信号后,可以做一些准备工作,再进行程序终止。
有的时候,kill -15无法终止程序,因为他可能被忽略,这时候可以使用kill -9,系统会发出SIGKILL(9)信号,该信号不允许忽略和阻塞,所以应用程序会立即终止。
这也会带来很多副作用,如数据丢失等,所以,在非必要时,不要使用kill -9命令,尤其是那些web应用、提供RPC服务、执行定时任务、包含长事务等应用中,因为kill -9 没给spring容器、tomcat服务器、dubbo服务、流程引擎、状态机等足够的时间进行收尾。
最后,很多人会说,说了这么多,不是还得用 kill -9 吗?
其实,本文的目的不是不让大家用,那就是因噎废食了。本文是希望大家可以了解其背后的原理,知道他可能带来的副作用。在选择要不要执行的时候,可以考虑到这些因素,如果能够针对可能发生的副作用,提前做好预案和心理准备,然后再执行,那就很完美了。