Adición de enlaces de cierre para aplicaciones JVM

1. Información general

Normalmente es fácil poner en marcha un servicio. Sin embargo, a veces necesitamos tener un plan para cerrar uno con gracia.

En este tutorial, veremos las diferentes formas en que una aplicación JVM puede terminar. Luego, usaremos las API de Java para administrar los ganchos de cierre de JVM. Consulte este artículo para obtener más información sobre cómo cerrar la JVM en aplicaciones Java.

2. Cierre de JVM

La JVM se puede cerrar de dos formas diferentes:

  1. Un proceso controlado
  2. Una manera abrupta

Un proceso controlado apaga la JVM cuando:

  • El último subproceso que no es demonio termina. Por ejemplo, cuando el hilo principal sale, la JVM inicia su proceso de cierre.
  • Envío de una señal de interrupción desde el sistema operativo. Por ejemplo, presionando Ctrl + C o cerrando la sesión del sistema operativo
  • Llamar a System.exit () desde código Java

Si bien todos nos esforzamos por lograr cierres agradables, a veces la JVM puede cerrarse de manera abrupta e inesperada. La JVM se apaga abruptamente cuando :

  • Envío de una señal de muerte desde el sistema operativo. Por ejemplo, emitiendo un kill -9
  • Llamar a Runtime.getRuntime (). Halt () desde el código Java
  • El sistema operativo del host muere inesperadamente, por ejemplo, en un corte de energía o pánico del sistema operativo

3. Ganchos de apagado

La JVM permite que las funciones de registro se ejecuten antes de que finalice su cierre. Estas funciones suelen ser un buen lugar para liberar recursos u otras tareas domésticas similares. En la terminología de JVM, estas funciones se denominan ganchos directos .

Los enlaces de cierre son básicamente subprocesos inicializados pero no iniciados . Cuando la JVM comienza su proceso de cierre, iniciará todos los ganchos registrados en un orden no especificado. Después de ejecutar todos los ganchos, la JVM se detendrá.

3.1. Agregar ganchos

Para agregar un gancho de cierre, podemos usar el método Runtime.getRuntime (). AddShutdownHook () :

Thread printingHook = new Thread(() -> System.out.println("In the middle of a shutdown")); Runtime.getRuntime().addShutdownHook(printingHook);

Aquí simplemente imprimimos algo en la salida estándar antes de que JVM se apague. Si cerramos la JVM como sigue:

> System.exit(129); In the middle of a shutdown

Luego veremos que el gancho realmente imprime el mensaje en la salida estándar.

La JVM es responsable de iniciar los subprocesos de enlace . Por lo tanto, si el gancho dado ya se ha iniciado, Java lanzará una excepción:

Thread longRunningHook = new Thread(() -> { try { Thread.sleep(300); } catch (InterruptedException ignored) {} }); longRunningHook.start(); assertThatThrownBy(() -> Runtime.getRuntime().addShutdownHook(longRunningHook)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Hook already running"); 

Obviamente, tampoco podemos registrar un gancho varias veces:

Thread unfortunateHook = new Thread(() -> {}); Runtime.getRuntime().addShutdownHook(unfortunateHook); assertThatThrownBy(() -> Runtime.getRuntime().addShutdownHook(unfortunateHook)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Hook previously registered");

3.2. Quitar ganchos

Java proporciona un método de eliminación doble para eliminar un gancho de apagado en particular después de registrarlo:

Thread willNotRun = new Thread(() -> System.out.println("Won't run!")); Runtime.getRuntime().addShutdownHook(willNotRun); assertThat(Runtime.getRuntime().removeShutdownHook(willNotRun)).isTrue(); 

El método removeShutdownHook () devuelve verdadero cuando el gancho de cierre se elimina con éxito.

3.3. Advertencias

La JVM ejecuta cierres de gancho solo en caso de terminaciones normales. Por lo tanto, cuando una fuerza externa mata el proceso de JVM abruptamente, la JVM no tendrá la oportunidad de ejecutar hooks de cierre. Además, detener la JVM desde el código Java también tendrá el mismo efecto:

Thread haltedHook = new Thread(() -> System.out.println("Halted abruptly")); Runtime.getRuntime().addShutdownHook(haltedHook); Runtime.getRuntime().halt(129); 

El método de detención finaliza a la fuerza la JVM que se está ejecutando actualmente. Por lo tanto, los ganchos de cierre registrados no tendrán la oportunidad de ejecutarse.

4. Conclusión

En este tutorial, analizamos diferentes formas en que una aplicación JVM puede terminar. Luego, usamos algunas API en tiempo de ejecución para registrar y anular el registro de los ganchos de cierre.

Como de costumbre, el código de muestra está disponible en GitHub.