当程序收到kill信号时,你如何处理清理?
例如,我连接的应用程序需要任何第三方应用程序(我的应用程序)finish在注销时发送命令.finish当我的应用程序被摧毁时,发送该命令的最佳发音是kill -9什么?
编辑1:无法捕获kill -9.谢谢你们纠正我.
编辑2:我想这种情况是当一个人调用kill时与ctrl-c相同
小智 123
处理此问题的方法除了注册关闭钩子之外的任何其他方法.如果你可以使用(SIGTERM),那么关闭钩子就可以了.(SIGINT)DOES导致程序正常退出并运行关闭挂钩.kill -9kill -15kill -2
注册新的虚拟机关闭挂钩.
Java虚拟机关闭以响应两种事件:
- 当最后一个非守护程序线程退出或调用退出(等效,System.exit)方法时,程序正常退出,或者
- 响应于用户中断(例如,键入^ C)或系统范围的事件(例如用户注销或系统关闭),终止虚拟机.
我试图在OSX 10.6.3及以下的测试程序kill -9就没有不运行关闭挂钩,符合市场预期.在kill -15它DOES运行关机钩每次.
public class TestShutdownHook
{
public static void main(String[] args) throws InterruptedException
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
@Override
public void run()
{
System.out.println("Shutdown hook ran!");
}
});
while (true)
{
Thread.sleep(1000);
}
}
}
Run Code Online (Sandbox Code Playgroud)
没有任何方法可以kill -9在任何程序中真正优雅地处理.
在极少数情况下,虚拟机可能会中止,即停止运行而不会干净地关闭.当虚拟机在外部终止时会发生这种情况,例如Unix上的SIGKILL信号或Microsoft Windows上的TerminateProcess调用.
处理a的唯一真正选择kill -9是让另一个观察程序监视主程序消失或使用包装脚本.您可以使用shell脚本来执行此操作,该脚本轮询ps命令以在列表中查找您的程序,并在消失时相应地执行操作.
#!/usr/bin/env bash
java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"
Run Code Online (Sandbox Code Playgroud)
Asg*_*sen 13
有一些方法可以在某些JVM中处理您自己的信号 - 例如,请参阅有关HotSpot JVM的文章.
通过使用Sun内部sun.misc.Signal.handle(Signal, SignalHandler)方法调用,您还可以注册信号处理程序,但可能不适用于JVM使用的信号INT或TERM它们使用的信号.
为了能够处理任何信号,您必须跳出JVM并进入操作系统区域.
我通常做的(例如)检测异常终止是在Perl脚本中启动我的JVM,但让脚本使用waitpid系统调用等待JVM .
每当JVM退出时,我都会收到通知,以及退出的原因,并且可以采取必要的措施.
我希望JVM能够优雅地中断(thread.interrupt())应用程序创建的所有正在运行的线程,至少对于信号SIGINT (kill -2)和SIGTERM (kill -15).
这样,信号将被转发给它们,允许以标准方式正常地取消线程和资源完成.
但事实并非如此(至少在我的JVM实现中:Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode).
正如其他用户评论的那样,关闭钩子的使用似乎是强制性的.
那么,我该如何处理呢?
首先,我不关心它在所有程序中,只在那些我想跟踪用户取消和意外结束的程序中.例如,假设您的java程序是由其他人管理的进程.您可能希望区分它是否已正常终止(SIGTERM来自管理器进程)或已发生关闭(以便在启动时自动重新启动作业).
作为一个基础,我总是让我长时间运行的线程周期性地意识到中断状态,InterruptedException如果他们中断就扔掉.这使得能够以开发人员控制的方式执行最终确定(也产生与标准阻塞操作相同的结果).然后,在线程堆栈的顶层InterruptedException捕获并执行适当的清理.这些线程被编码为已知如何响应中断请求.高凝聚力设计.
所以,在这些情况下,我添加了一个关闭钩子,这就是我认为JVM默认应该做的事情:中断我的应用程序仍在运行的所有非守护程序线程:
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Interrupting threads");
Set<Thread> runningThreads = Thread.getAllStackTraces().keySet();
for (Thread th : runningThreads) {
if (th != Thread.currentThread()
&& !th.isDaemon()
&& th.getClass().getName().startsWith("org.brutusin")) {
System.out.println("Interrupting '" + th.getClass() + "' termination");
th.interrupt();
}
}
for (Thread th : runningThreads) {
try {
if (th != Thread.currentThread()
&& !th.isDaemon()
&& th.isInterrupted()) {
System.out.println("Waiting '" + th.getName() + "' termination");
th.join();
}
} catch (InterruptedException ex) {
System.out.println("Shutdown interrupted");
}
}
System.out.println("Shutdown finished");
}
});
Run Code Online (Sandbox Code Playgroud)
在github上完成测试应用程序:https://github.com/idelvall/kill-test
参考https://aws.amazon.com/blogs/containers/graceful-shutdowns-with-ecs/
import sun.misc.Signal;
import sun.misc.SignalHandler;
public class ExampleSignalHandler {
public static void main(String... args) throws InterruptedException {
final long start = System.nanoTime();
Signal.handle(new Signal("TERM"), new SignalHandler() {
public void handle(Signal sig) {
System.out.format("\nProgram execution took %f seconds\n", (System.nanoTime() - start) / 1e9f);
System.exit(0);
}
});
int counter = 0;
while(true) {
System.out.println(counter++);
Thread.sleep(500);
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用Runtime.getRuntime().addShutdownHook(...),但不能保证在任何情况下都会调用它.
| 归档时间: |
|
| 查看次数: |
93536 次 |
| 最近记录: |