Cómo detener el proceso de Java con gracia?

¿Cómo detengo un proceso de Java con gracia en Linux y Windows?

¿ Runtime.getRuntime().addShutdownHook se llama a Runtime.getRuntime().addShutdownHook y cuándo no?

¿Qué hay de los finalizadores? ¿Ayudan aquí?

¿Puedo enviar algún tipo de señal a un proceso de Java desde un shell?

Estoy buscando soluciones preferiblemente portátiles.

Los ganchos de cierre se ejecutan en todos los casos en que la máquina virtual no muere por la fuerza. Entonces, si emitieras un kill “estándar” ( SIGTERM desde un comando kill) entonces se ejecutarán. Del mismo modo, se ejecutarán después de llamar a System.exit(int) .

Sin embargo, una muerte fuerte ( kill -9 o kill -SIGKILL ) entonces no se ejecutarán. Del mismo modo (y obviamente) no se ejecutarán si extraes la energía de la computadora, la dejas caer en una cuba de lava hirviendo o golpeas la CPU en pedazos con un mazo. Sin embargo, probablemente ya lo sabías.

Los finalizadores realmente deberían ejecutarse también, pero es mejor no confiar en eso para la limpieza del cierre, sino confiar en sus ganchos de apagado para detener las cosas limpiamente. Y, como siempre, tenga cuidado con los interlockings (¡he visto demasiados ganchos de apagado que bloquean todo el proceso)!

Ok, después de todas las posibilidades que he elegido para trabajar con “Java Monitoring and Management”
La descripción está aquí
Eso le permite controlar una aplicación desde otra de una manera relativamente fácil. Puede llamar a la aplicación de control desde una secuencia de comandos para detener la aplicación controlada con gracia antes de matarla.

Aquí está el código simplificado:

Aplicación controlada:
ejecutarlo con los siguientes parámetros de VM:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port = 9999
-Dcom.sun.management.jmxremote.authenticate = false
-Dcom.sun.management.jmxremote.ssl = false

 //ThreadMonitorMBean.java public interface ThreadMonitorMBean { String getName(); void start(); void stop(); boolean isRunning(); } // ThreadMonitor.java public class ThreadMonitor implements ThreadMonitorMBean { private Thread m_thrd = null; public ThreadMonitor(Thread thrd) { m_thrd = thrd; } @Override public String getName() { return "JMX Controlled App"; } @Override public void start() { // TODO: start application here System.out.println("remote start called"); } @Override public void stop() { // TODO: stop application here System.out.println("remote stop called"); m_thrd.interrupt(); } public boolean isRunning() { return Thread.currentThread().isAlive(); } public static void main(String[] args) { try { System.out.println("JMX started"); ThreadMonitorMBean monitor = new ThreadMonitor(Thread.currentThread()); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName name = new ObjectName("com.example:type=ThreadMonitor"); server.registerMBean(monitor, name); while(!Thread.interrupted()) { // loop until interrupted System.out.println("."); try { Thread.sleep(1000); } catch(InterruptedException ex) { Thread.currentThread().interrupt(); } } } catch(Exception e) { e.printStackTrace(); } finally { // TODO: some final clean up could be here also System.out.println("JMX stopped"); } } } 

Aplicación de control:
ejecutarlo con la parada o comenzar como el argumento de la línea de comando

 public class ThreadMonitorConsole { public static void main(String[] args) { try { // connecting to JMX System.out.println("Connect to JMX service."); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi"); JMXConnector jmxc = JMXConnectorFactory.connect(url, null); MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); // Construct proxy for the the MBean object ObjectName mbeanName = new ObjectName("com.example:type=ThreadMonitor"); ThreadMonitorMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, ThreadMonitorMBean.class, true); System.out.println("Connected to: "+mbeanProxy.getName()+", the app is "+(mbeanProxy.isRunning() ? "" : "not ")+"running"); // parse command line arguments if(args[0].equalsIgnoreCase("start")) { System.out.println("Invoke \"start\" method"); mbeanProxy.start(); } else if(args[0].equalsIgnoreCase("stop")) { System.out.println("Invoke \"stop\" method"); mbeanProxy.stop(); } // clean up and exit jmxc.close(); System.out.println("Done."); } catch(Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 

Eso es. 🙂

Otra forma: su aplicación puede abrir un servidor y esperar a que llegue la información. Por ejemplo, una cadena con una palabra “mágica” 🙂 y luego reactjsr para cerrar: System.exit (). Puede enviar dicha información al sockete usando una aplicación externa como Telnet.

Pregunta similar aquí

Los finalizadores en Java son malos. Agregan una gran cantidad de sobrecarga a la recolección de basura. Evítalos siempre que sea posible.

El shutdownHook solo se ejecutará cuando la VM se cierre. Creo que muy bien puede hacer lo que quieras.

Aquí hay una solución un poco complicada, pero portátil:

  • En su aplicación, implemente un gancho de apagado
  • Cuando desee cerrar correctamente su JVM, instale un Agente de Java que llame a System.exit () utilizando la API de conexión .

Implementé el Agente de Java. Está disponible en Github: https://github.com/everit-org/javaagent-shutdown

La descripción detallada de la solución está disponible aquí: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/

La señalización en Linux se puede hacer con “kill” (matar por las señales disponibles), necesitaría la identificación del proceso para hacerlo. (ps ax | grep java) o algo así, o guarde la identificación del proceso cuando se crea el proceso (esto se usa en la mayoría de los archivos de inicio de Linux, consulte /etc/init.d)

La señalización portátil se puede hacer integrando un SocketServer en su aplicación java. No es tan difícil y te da la libertad de enviar cualquier comando que desees.

Si se refería a las cláusulas finales en lugar de a los finalizadores; no se extienden cuando se llama a System.exit (). Los finalizadores deberían funcionar, pero en realidad no deberían hacer nada más significativo, sino imprimir una statement de depuración. Ellos son peligrosos.

Gracias por tus respuestas. Shutdown engancha las costuras como algo que funcionaría en mi caso. Pero también me topé con lo que se llama beans Monitoring and Management:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Eso ofrece algunas buenas posibilidades para el monitoreo remoto y la manipulación del proceso de java. (Fue introducido en Java 5)