¿Cómo detengo un proceso de Java correctamente en Linux y Windows?
¿Cuándo Runtime.getRuntime().addShutdownHook
se llama y cuándo no?
¿Qué pasa con los finalizadores? ¿Ayudan aquí?
¿Puedo enviar algún tipo de señal a un proceso de Java desde un shell?
Busco soluciones preferiblemente portátiles.
Respuestas:
Los enganches de cierre se ejecutan en todos los casos en los que la máquina virtual no se mata a la fuerza. Entonces, si tuviera que emitir un kill "estándar" (
SIGTERM
desde un comando kill), se ejecutarán. Del mismo modo, se ejecutarán después de llamarSystem.exit(int)
.Sin embargo, una muerte difícil (
kill -9
okill -SIGKILL
) no se ejecutará. De manera similar (y obviamente) no se ejecutarán si extrae la energía de la computadora, la deja caer en una tina de lava hirviendo o golpea la CPU en pedazos con un mazo. Sin embargo, probablemente ya lo sabías.Los finalizadores también deberían ejecutarse, pero es mejor no confiar en eso para la limpieza del apagado, sino confiar en sus ganchos de apagado para detener las cosas de manera limpia. Y, como siempre, tenga cuidado con los interbloqueos (he visto demasiados ganchos de apagado que cuelgan todo el proceso).
fuente
Ok, después de todas las posibilidades que he elegido para trabajar con "Monitorización y administración de Java". La
descripción general está aquí.
Esto le permite controlar una aplicación desde otra de una manera relativamente fácil. Puede llamar a la aplicación de control desde un script para detener la aplicación controlada correctamente antes de matarla.
Aquí está el código simplificado:
Aplicación controlada:
ejecútela 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 = falso
//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:
ejecútela con la parada o inicio como argumento de 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. :-)
fuente
De otra forma: su aplicación puede abrir un servidor socet y esperar a que llegue una información. Por ejemplo, una cadena con una palabra "mágica" :) y luego reacciona para hacer shutdown: System.exit (). Puede enviar dicha información al socke mediante una aplicación externa como telnet.
fuente
Aquí hay una solución un poco complicada, pero portátil:
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/
fuente
Pregunta similar aquí
Los finalizadores en Java son malos. Añaden una gran cantidad de gastos generales a la recolección de basura. Evítelos siempre que sea posible.
El shutdownHook solo se llamará cuando la VM se esté apagando. Creo que muy bien puede hacer lo que quieras.
fuente
La señalización en Linux se puede hacer con "kill" (man kill para las señales disponibles), necesitaría el ID del proceso para hacer eso. (ps ax | grep java) o algo así, o almacene 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 realizar 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 te refieres a cláusulas de final en lugar de 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 que imprimir una declaración de depuración. Son peligrosos.
fuente
Gracias por tus respuestas. El cierre cierra las costuras como algo que funcionaría en mi caso. Pero también me encontré con lo que se llama beans de monitoreo y administración:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Eso brinda algunas buenas posibilidades, para el monitoreo remoto y la manipulación del proceso java. (Fue introducido en Java 5)
fuente