优先使用 kill -15 pid
, 实在退出不了再用kill -9 pid
。
kill pid
等同于 kill -15 pid
。
kill命令可以发送信号给进程,15和9都是信号的编号。15代表SIGTERM,表示正常停止进程,进程可以在退出前完成一些收尾工作; 9代表SIGKILL,表示强制停止进程。
kill -l
可以列出所有信号。
pkill可以根据关键字给进程发送信号,例如: pkill -15 -f test-2.0.0.0.jar
在Java代码中,可以通过Runtime.getRuntime().addShutdownHook()添加进程停止时的钩子来实现优雅关机。在这个hook中我们可以完成释放资源、保存程序运行时的状态等操作。
spingboot项目优雅关机示例如下:
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
Runtime.getRuntime().addShutdownHook(new Thread(ctx::close, "shutdownHook"));
addShutdownHook方法的参数是Thread,我们可以指定进程收到停止信号后所要做的事情(Runnable接口的实现类的匿名对象)。在进程收到SIGTERM即15这个信号时,这个线程就会运行。
ApplicationContext.close()方法中会调用所有DisposableBean的destroy方法,一般通过实现DisposableBean来完成资源释放等操作,例如:
@Component
public class ThreadManager implements DisposableBean {
@Override
public void destroy() throws Exception {
// TODO
}
}
有一点要注意,进程在收到SIGTERM这个信号后,其他用户线程都停止了,只有addShutdownHook指定的线程在工作。所以你的收尾工作只能在hook线程中执行。一个错误示例如下:
volatile boolean run = true;
public void run() {
// 业务线程运行这段代码
while (this.run) {
// 1.do something
}
// 2.释放资源
}
// shutdownHook中调用这个方法
public void stop() {
this.run = false;
}
上面2处的代码不会执行,因为在收到SIGTERM信号后业务线程停止了,只有hook线程在运行,应该改成这样:
volatile boolean run = true;
public void run() {
// 业务线程运行这段代码
while (this.run) {
// 1.do something
}
}
// shutdownHook中调用这个方法
public void stop() {
// 2.释放资源
}