问题
当程序收到终止信号时,你如何处理清理?
例如,我连接的应用程序需要任何第三方应用程序(我的应用程序)在注销时发送一个finish
命令。当我的应用程序被akill -9
销毁时,发送该finish
命令的最佳发音是什么?
编辑1:无法捕获kill -9。谢谢你们纠正我。
编辑2:我猜这种情况是当一个人调用kill时与ctrl-c相同
#1 热门回答(107 赞)
处理这个任何事情的方法其他thankill -9
将注册ashutdownhook。如果可以使用(SIGTERM)kill -15
,则关闭钩子将起作用。 (SIGINT)kill -2
DOES因为程序正常退出并运行关闭挂钩。
注册新的虚拟机关闭挂钩。 Java虚拟机关闭以响应两种事件:当最后一个非守护程序线程退出时,程序正常退出或
调用exit(等效,System.exit)方法时,或虚拟机终止以响应用户
中断,例如键入^ C,或系统范围的事件,例如用户注销或系统关闭。
我尝试了OSX 10.6.3上的以下测试程序和onkill -9
it didNOTrun关闭钩子,没想到会。在akill -15
itDOES每次都关闭挂钩。
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);
}
}
}
没有任何方法可以在任何程序中真正优雅地处理akill -9
。
在极少数情况下,虚拟机可能会中止,即停止运行而不会干净地关闭。当虚拟机在外部终止时会发生这种情况,例如Unix上的SIGKILL信号或Microsoft Windows上的TerminateProcess调用。
处理akill -9
的唯一真正选择是让另一个观察程序监视你的主程序消失或使用包装脚本。你可以使用shell脚本来执行此操作,该脚本轮询ps
命令在列表中查找你的程序,并在消失时相应地执行操作。
#!/usr/bin/env bash
java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"
#2 热门回答(12 赞)
在某些JVM中可以处理自己的信号 - 例如,参见this article about the HotSpot JVM。
通过使用Sun internalsun.misc.Signal.handle(Signal, SignalHandler)
方法调用,你还可以注册信号处理程序,但可能不适用于JVM使用的信号,如INT
或TERM
。
为了能够处理信号,你必须跳出JVM并进入操作系统区域。
我通常做的(例如)检测异常终止是在Perl脚本中启动我的JVM,但让脚本使用waitpid
系统调用等待JVM。
每当JVM退出时,我都会收到通知,以及退出的原因,并且可以采取必要的措施。
#3 热门回答(6 赞)
你可以使用Runtime.getRuntime().addShutdownHook(...)
,但不能保证在任何情况下都会调用它。