当Java接收到kill信号时,为什么主线程没有运行完毕?

时间:2019-01-21 13:03:31

标签: java interrupt kill-process

所以我有这个代码块:

package com.stackoverflow.jontejj.killsignal;
public class Problem {
    public static void main(String[] args) {
        try {
            System.out.println("Executing");
            Thread.sleep(1000000);
            System.out.println("Done sleeping");
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
            throw new RuntimeException(e);
        }
        System.out.println("Finished");
    }

}

而且我正尝试中止主要方法

    kill -15 <pid>

我希望它能显示“ Interrupted”和一个堆栈跟踪信息,但是该程序只是直接被杀死。我应该如何优雅地处理杀伤信号?

1 个答案:

答案 0 :(得分:0)

默认行为记录在Runtime#addShutdownHook中:

  

在极少数情况下,虚拟机可能会中止,即停止运行而不会完全关闭。当虚拟机在外部终止时会发生这种情况,例如在Unix上使用SIGKILL信号或在Microsoft Windows上使用TerminateProcess调用。如果本机方法出错(例如,破坏内部数据结构或尝试访问不存在的内存),则虚拟机也可能中止。如果虚拟机中止,则无法保证是否将运行任何关闭挂钩。

要解决此问题并在终止信号上发送中断,您可以执行以下操作:

package com.stackoverflow.jontejj.killsignal;
public class Solution {
    public static void main(String[] args) {
        Thread main = Thread.currentThread();
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                main.interrupt();
                main.join(); //Possibly with a timeout here
            } catch (InterruptedException e1) {
                Thread.currentThread().interrupt();
            }
        }));
        try {
            Thread.sleep(1000000);
            System.out.println("Done sleeping");
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
            throw new RuntimeException(e);
        }
        System.out.println("Bye");
    }
}

这将导致:

Interrupted
Exception in thread "main" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted
    at java_stopping/com.stackoverflow.jontejj.killsignal.Solution.main(Solution.java:18)
Caused by: java.lang.InterruptedException: sleep interrupted
    at java.base/java.lang.Thread.sleep(Native Method)
    at java_stopping/com.stackoverflow.jontejj.killsignal.Solution.main(Solution.java:14)

在收到终止信号时被打印。