Esperaría que la JVM interrumpa con gracia ( thread.interrupt()
) todos los subprocesos en ejecución creados por la aplicación, al menos para las señales SIGINT (kill -2)
y SIGTERM (kill -15)
.
De esta manera, la señal se les enviará, lo que permitirá una elegante cancelación de subprocesos y finalización de recursos en las formas estándar .
Pero este no es el caso (al menos en mi aplicación 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)
.
Como comentaron otros usuarios, el uso de ganchos de cierre parece obligatorio.
Entonces, ¿cómo lo manejaría?
Bueno, primero, no me importa en todos los programas, solo en aquellos en los que quiero hacer un seguimiento de las cancelaciones de usuarios y los finales inesperados. Por ejemplo, imagine que su programa java es un proceso administrado por otro. Es posible que desee diferenciar si se ha terminado correctamente ( SIGTERM
del proceso del administrador) o si se ha producido un cierre (para reiniciar automáticamente el trabajo al inicio).
Como base, siempre hago que mis hilos de larga duración sean conscientes periódicamente del estado interrumpido y lanzo un mensaje InterruptedException
si se interrumpieron. Esto permite la finalización de la ejecución de forma controlada por el desarrollador (que también produce el mismo resultado que las operaciones de bloqueo estándar). Luego, en el nivel superior de la pila de subprocesos, InterruptedException
se captura y se realiza la limpieza adecuada. Estos hilos están codificados para saber cómo responder a una solicitud de interrupción. Diseño de alta cohesión .
Entonces, en estos casos, agrego un gancho de apagado, que hace lo que creo que la JVM debería hacer de manera predeterminada: interrumpir todos los subprocesos que no son demonios creados por mi aplicación que aún se están ejecutando:
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");
}
});
Solicitud de prueba completa en github: https://github.com/idelvall/kill-test
kill -9
significa para mí: "¡Vete, proceso inmundo, vete!", tras lo cual el proceso dejará de existir. Inmediatamente.