Как изящно обрабатывать сигнал SIGKILL в Java
как вы обрабатываете очистку, когда программа получает сигнал убийства?
например, есть приложение, к которому я подключаюсь, которое хочет, чтобы любое стороннее приложение (мое приложение) отправило finish
команда при выходе из системы. Что лучше сказать, чтобы отправить это finish
команда, когда мое приложение было уничтожено с kill -9
?
edit 1: kill -9 не может быть захвачен. Спасибо, что поправили меня.
edit 2: я думаю, этот случай будет, когда один вызовет только kill, который совпадает с ctrl-C
5 ответов
способ справиться с этим ничего другое чем kill -9
было бы зарегистрировать остановка крюк. Если вы можете использовать (команды SIGTERM) kill -15
крюк выключения будет работать. (РЭР) 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
это попросите другую программу watcher следить за вашей основной программой, чтобы уйти или использовать сценарий обертки. Вы можете сделать это с помощью сценария оболочки, который опросил ps
команда ищет вашу программу в списке и действует соответственно, когда она исчезла.
#!/usr/bin/env bash
java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"
здесь are способы обработки ваших собственных сигналов в некоторых JVMs-см эта статья о 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 должен теоретически знать, что он / она делает, и что это может оставить вещи в несогласованное состояние.