Je m'attendrais à ce que la JVM interrompt gracieusement ( thread.interrupt()
) tous les threads en cours d'exécution créés par l'application, au moins pour les signaux SIGINT (kill -2)
et SIGTERM (kill -15)
.
De cette façon, le signal leur sera transmis, permettant une annulation de thread et une finalisation des ressources en douceur de la manière standard .
Mais ce n'est pas le cas (au moins dans ma mise en œuvre 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)
.
Comme l'ont commenté d'autres utilisateurs, l'utilisation de hooks d'arrêt semble obligatoire.
Alors, comment puis-je gérer cela?
Eh bien d'abord, je m'en fiche dans tous les programmes, seulement dans ceux où je veux garder une trace des annulations d'utilisateurs et des fins inattendues. Par exemple, imaginez que votre programme java est un processus géré par d'autres. Vous voudrez peut-être différencier s'il a été terminé correctement (à SIGTERM
partir du processus gestionnaire) ou si un arrêt s'est produit (afin de relancer automatiquement le travail au démarrage).
Comme base, je rends toujours mes threads de longue durée régulièrement au courant de l'état interrompu et jette un message InterruptedException
s'ils sont interrompus. Cela permet la finalisation de l'exécution de manière contrôlée par le développeur (produisant également le même résultat que les opérations de blocage standard). Ensuite, au niveau supérieur de la pile de threads, InterruptedException
est capturé et un nettoyage approprié est effectué. Ces threads sont codés pour savoir comment répondre à une demande d'interruption. Conception à haute cohésion .
Donc, dans ces cas, j'ajoute un hook d'arrêt, qui fait ce que je pense que la JVM devrait faire par défaut: interrompre tous les threads non démon créés par mon application qui sont toujours en cours d'exécution:
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");
}
});
Application de test complète sur github: https://github.com/idelvall/kill-test
kill -9
signifie pour moi: "Pars, processus immonde, loin avec toi!", sur lequel le processus cessera d'être. Immédiatement.