2008-10-10 23 views
82

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

¿Cuándo 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.

+0

que realmente debe definir lo que entendemos por gracia. (por favor) –

+6

Supongo que quieren decir que quieren tener la oportunidad de limpiar un recurso, liberar, bloquear y enjuagar cualquier dato persistente en el disco antes de que se mate el programa. –

Respuesta

72

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

Sin embargo, una muerte fuerte (kill -9 o kill -SIGKILL) 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 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 de forma limpia. Y, como siempre, tenga cuidado con los interbloqueos (¡he visto demasiados ganchos de apagado que bloquean todo el proceso)!

+0

Desafortunadamente, esto no parece funcionar en Windows 7 (64 bits). He intentado usar taskill, sin el indicador de fuerza, y encuentro el siguiente error: "ERROR: El proceso con PID 14324 no se pudo terminar. Motivo: Este proceso solo puede finalizar con fuerza (con la opción/F)". Al suministrar la opción de fuerza, "/ f", obviamente se cerrará el proceso al instante. –

+0

No puede confiar en que se ejecuten los finalizadores. –

2

pregunta similar Here

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

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

+1

Entonces shutdownHook se llama en TODOS los casos? ¿Qué pasa si 'matar' el proceso de shell? – Ma99uS

+0

Bueno, no si lo estás matando -9 :) –

0

señalización en Linux se puede hacer con "matar" (hombre mata por las señales disponibles), lo que se necesita el ID del proceso de hacer eso. (ps ax | grep java) o algo así, o almacenar el id del proceso cuando se crea el proceso (esto se usa en la mayoría de los archivos de inicio de Linux, vea /etc/init.d)

La señalización portátil se puede realizar mediante 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 finalmente a las cláusulas 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 declaración de depuración. Ellos son peligrosos.

0

Gracias por sus 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
Esto ofrece algunas buenas posibilidades para la monitorización remota y la manipulación del proceso java.(Se introdujo en Java 5)

46

Ok, después de todas las posibilidades que he elegido para trabajar con "Monitoreo Java y gestión"
Overview is here
Eso le permite controlar una aplicación de otro en forma 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.

Este es el código simplificado:

aplicación controlada:
plazo con los parámetros de VM folowing:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote .port = 9,999
-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:
plazo con el parada o arranque como el argumento de línea de comandos

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 todo. :-)

7

De 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 reaccionar para cerrar: System.exit(). Puede enviar dicha información al sockete usando una aplicación externa como Telnet.

Cuestiones relacionadas