Я б очікував, що 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
kill -9
означає для мене: "Почався, недобрий процес, геть з тобою!", після якого процес перестане бути. Відразу.