Как изящно обрабатывать сигнал SIGKILL на Java



как вы справляетесь с очисткой, когда программа получает сигнал убийства?



например, есть приложение, к которому я подключаюсь, которое хочет, чтобы любое стороннее приложение (мое приложение) отправляло finish команда при выходе из системы. Что лучше всего сказать, чтобы отправить это finish команда, когда мое приложение было уничтожено с kill -9?



изменить 1: убить -9 не может быть захвачен. Спасибо, ребята, что поправили меня.



edit 2: я думаю, этот случай будет, когда один звонит просто убить, что то же самое, что ctrl-c

487   5  

5 ответов:

способ справиться с этим ничего другое чем kill -9 было бы зарегистрировать остановка крюк. Если вы можете использовать (SIGTERM)kill -15 крюк выключения будет работать. (SIGINT)kill -2тут вызвать программу, чтобы корректно завершить работу и запустить рычаги завершения работы.

регистрирует новую виртуальную машину рычаг завершения работы.

виртуальная машина Java завершает работу в ответ к двум видам событий:

* The program exits normally, when the last non-daemon thread exits or

когда выход (эквивалентно, Система.exit) вызывается метод, или

* The virtual machine is terminated in response to a user

прерывание, например ввод ^C или a системные события, такие как выход пользователя из системы или выключение системы.

я попробовал следующую тестовую программу на OSX 10.6.3 и на kill -9 это ничего не запустите крюк выключения, не думал, что это будет. На kill -15 это тут запустите крюк выключения каждый время.

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

нет никакого способа действительно изящно обращаться с kill -9 в любой программе.

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

единственный реальный вариант для обработки kill -9 is to попросите другую программу-наблюдатель следить за вашей основной программой, чтобы уйти или использовать сценарий обертки. Вы могли бы сделать это с помощью сценария оболочки, который опросил ищем программу в списке и действовать соответственно, когда он исчез.

#!/usr/bin/env bash

java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"

здесь are способы для обработки ваших собственных сигналов в определенные виртуальные машины -- см. эта статья о HotSpot JVM например.

С помощью внутреннего Солнца sun.misc.Signal.handle(Signal, SignalHandler) вызов метода, вы также можете зарегистрировать обработчик сигнала, но, вероятно, не для сигналов типа INT или TERM как они используются JVM.

чтобы иметь возможность обрабатывать любой сигнал вам придется прыгать из JVM и в операционную систему территория.

то, что я обычно делаю (например) для обнаружения ненормального завершения, - это запуск моей JVM внутри скрипта Perl, но сценарий ждет JVM с помощью waitpid системный вызов.

затем мне сообщают, когда JVM выходит, и почему он вышел, и может предпринять необходимые действия.

можно использовать Runtime.getRuntime().addShutdownHook(...), но вы не можете быть уверены, что он будет называться в любом случае.

Я ожидал бы, что 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");
    }
});

полное тестовое приложение на github:https://github.com/idelvall/kill-test

есть один способ реагировать на убийство -9: то есть иметь отдельный процесс, который контролирует процесс убивают и очищает после него, если это необходимо. Это, вероятно, будет связано с IPC и будет довольно много работы, и вы все равно можете переопределить его, убив оба процесса одновременно. Я предполагаю, что это не стоит в большинстве случаев.

тот, кто убивает процесс с -9 теоретически должны знать, что он/она делает, и что он может оставить вещи в несогласованное состояние.

Comments

    Ничего не найдено.