Mi aspetto che la JVM interrompa con grazia ( thread.interrupt()
) tutti i thread in esecuzione creati dall'applicazione, almeno per i segnali SIGINT (kill -2)
e SIGTERM (kill -15)
.
In questo modo, il segnale verrà inoltrato a loro, consentendo un'elegante cancellazione del thread e la finalizzazione delle risorse nei modi standard .
Ma questo non è il caso (almeno nella mia implementazione 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)
.
Come hanno commentato altri utenti, l'uso di hook di spegnimento sembra obbligatorio.
Quindi, come lo gestirò?
Ebbene prima di tutto, non mi interessa in tutti i programmi, solo in quelli in cui voglio tenere traccia delle cancellazioni degli utenti e dei fini imprevisti. Ad esempio, immagina che il tuo programma java sia un processo gestito da altri. Potresti voler distinguere se è stato terminato normalmente ( SIGTERM
dal processo di gestione) o si è verificato un arresto (per riavviare automaticamente il lavoro all'avvio).
Come base, rendo sempre i miei thread di lunga durata periodicamente consapevoli dello stato di interruzione e lancio un InterruptedException
se interrotto. Ciò consente la finalizzazione dell'esecuzione in modo controllato dallo sviluppatore (producendo anche lo stesso risultato delle operazioni di blocco standard). Quindi, al livello superiore dello stack di thread, InterruptedException
viene acquisito e viene eseguita la pulizia appropriata. Questi thread sono codificati per sapere come rispondere a una richiesta di interruzione. Design ad alta coesione .
Quindi, in questi casi, aggiungo un hook di spegnimento, che fa quello che penso che la JVM dovrebbe fare per impostazione predefinita: interrompere tutti i thread non daemon creati dalla mia applicazione che sono ancora in esecuzione:
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");
}
});
Applicazione di prova completa su github: https://github.com/idelvall/kill-test
kill -9
significa per me: "Vattene, fallo processo, via con te!", su cui il processo cesserà di essere. Subito.