Я ожидаю, что 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