如何在Java中优雅地处理SIGKILL信号

Beg*_*gui 106 java sigkill

当程序收到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 -15DOES运行关机钩每次.

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使用的信号INTTERM它们使用的信号.

为了能够处理任何信号,您必须跳出JVM并进入操作系统区域.

我通常做的(例如)检测异常终止是在Perl脚本中启动我的JVM,但让脚本使用waitpid系统调用等待JVM .

每当JVM退出时,我都会收到通知,以及退出的原因,并且可以采取必要的措施.

  • 注意你*可以*使用`sun.misc.Signal`捕获`INT`和`TERM`,但你不能处理`QUIT`,因为JVM保留它用于调试,也不能`KILL`,因为操作系统将终止JVM立即.试图处理任何一个都会引发一个`IllegalArgumentException`. (3认同)

ide*_*all 9

我希望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


dee*_*ank 8

参考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)


lex*_*ore 6

您可以使用Runtime.getRuntime().addShutdownHook(...),但不能保证在任何情况下都会调用它.

  • 但是在kill -9的情况下,它几乎肯定不会运行. (9认同)