基本概念
进程与线程:一个进程包含多个线程,一个进程中所有线程都退出后,该进程才会退出。
用户线程与守护线程:任一用户线程未退出,JVM进程不退出,当所有用户线程都退出时,
守护线程线程自动退出。
Shutdown hook:进程退出时执行的钩子,主要用来清理释放资源使进程友好的退出。为了避免强制退出JVM可能产生的各种问题,我们可以采用Shutdownhook、发出信号的方式,主动的通知JVM退出,并在JVM关闭前,执行应用程序的一些扫尾工作,进一步保证应用程序可以安全的退出。
Linux下与结束进程相关的信号量
名称 | 编号 | 功能 |
---|---|---|
SIGINT | 2 | 中断(同 Ctrl + C)会触发触发shutdownhook |
SIGKILL | 9 | 终止进程,强制杀死进程 |
SIGTERM | 15 | 终止进程,会先释放自己的资源,触发shutdownhook然后终止进程 |
Shutdown hook例子
public class TestShutdownHook {
public static void main(final String[] args) throws InterruptedException {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Shutdown hook ran!");
}
});
while (true) {
Thread.sleep(1000);
}
}
}
在linux环境下执行如上述代码,当通过kill -15 pid,kill -2 pid结束该Java进程时ShutdownHook会被调用。但Kill -9 pid不会触发ShutdownHook调用。当通过kill -9去结束一个Java进程时,则需要通过另一个程序来判断进程是否被关闭。例如通过shell脚本。
#!/bin/bash java TestShutdownHook wait # notify your other app that you quit echo "TestShutdownHook quit"
不友好的shutdown hook
shutdown hook内部陷入死循环,或被block住,会使进程无法退出。
public class Main {
public static void main(String[] args) throws Throwable {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("shutdown");
}catch (Exception e) {
}
}
}));
}
}
这种情况结合外部程序或脚本可以先发出kill -15,kill -2 如果一段时间内检测到进程未关闭,那么再发出kill -9来结束进程。