Почему основной поток не завершается, когда java получает сигнал уничтожения? - PullRequest
0 голосов
/ 21 января 2019

Итак, у меня есть этот блок кода:

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");
    }

}

И я пытаюсь прервать метод main с помощью

    kill -15 <pid>

И я ожидаю, что он напечатает «Прервано»и трассировка стека, но программа просто убита напрямую.Как я должен изящно обрабатывать сигналы убийства?

1 Ответ

0 голосов
/ 21 января 2019

Поведение по умолчанию задокументировано в Runtime # addShutdownHook :

В редких случаях виртуальная машина может прерваться, то есть прекратить работу, не выключившись полностью.Это происходит, когда виртуальная машина завершается извне, например, с помощью сигнала SIGKILL в Unix или вызова TerminateProcess в Microsoft Windows.Виртуальная машина также может прервать работу, если собственный метод не работает, например, из-за повреждения внутренних структур данных или попытки доступа к несуществующей памяти.Если виртуальная машина прерывает работу, то нельзя гарантировать, будут ли запущены какие-либо перехватчики завершения работы.

Чтобы обойти это поведение и отправить прерывание на сигналы уничтожения, вы можете сделать что-то похожее на это.:

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)

будет напечатано при получении сигнала уничтожения.

...