曾经遇到这样一个需求:就是在Eclipse上面运行Java程序的时候,中途点击Terminate按钮,想让程序退出前执行一段代码
代码如下:
package com.test;
public class TestShutdownHook {
static{
Runtime.getRuntime().addShutdownHook(new Thread(){
public void run(){
System.out.println("exit!");
}
});
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread thread = new MyThread();
thread.start();
}
static class MyThread extends Thread{
private int i = 3;
public MyThread(){
}
public void run(){
while(i > 0){
i--;
System.out.println("running...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
当程序正常退出或者在控制台上用java -jar TestShutdownHook.jar运行时按住Ctrl+C中断,都可以正常运行钩子中的代码:
但是如果在Eclipse上运行时,中途按Terminate强制退出时,钩子中代码不会运行:
Java 虚拟机会为了响应以下两类事件而关闭时:
- 程序正常退出:这发生在最后的非守护线程退出时,或者在调用 exit(等同于System.exit)方法时。
- 为响应用户中断而终止虚拟机:如键入 ^C;或发生系统事件,比如用户注销或系统关闭。
仅在很少的情况下,虚拟机可能会中止,也就是没有完全关闭就停止运行。比如在 Unix 上使用 SIGKILL 信号或者在 Microsoft Windows 上调用 TerminateProcess。如果由于内部数据结构损坏或试图访问不存在的内存而导致本机方法执行错误,那么可能也会中止虚拟机。如果虚拟机中止,则无法保证是否将运行关闭挂钩。【参考】
想想关闭钩子是基于JVM正常才能运行,如果JVM都挂掉了,还怎么可能运行钩子中代码,好比你命令一个士兵打完仗收拾战场,但是如果士兵战斗中牺牲,呵呵。