2008-10-10 19 views
82

Comment arrêter un processus Java correctement sous Linux et Windows?Comment arrêter le processus java avec élégance?

Quand est-ce que Runtime.getRuntime().addShutdownHook est appelée, et quand n'est-ce pas?

Qu'en est-il des finaliseurs, aident-ils ici? Puis-je envoyer une sorte de signal à un processus Java depuis un shell?

Je recherche des solutions de préférence portables.

+0

vous devriez vraiment définir ce que vous entendez par grâce. (SVP) –

+6

Je suppose qu'ils veulent dire qu'ils veulent avoir la possibilité de nettoyer des ressources, de libérer, verrouiller et vider toutes les données persistantes sur le disque avant que le programme ne soit tué. –

Répondre

72

Les crochets d'arrêt s'exécutent dans tous les cas où la VM n'est pas forcée. Donc, si vous deviez exécuter un kill "standard" (SIGTERM à partir d'une commande kill), ils s'exécuteront. De même, ils s'exécuteront après avoir appelé System.exit(int).

Toutefois, un arrêt brutal (kill -9 ou kill -SIGKILL) ne sera pas exécuté. De même (et évidemment) ils n'exécuteront pas si vous tirez le pouvoir de l'ordinateur, le jetez dans une cuve de lave bouillante, ou battez le CPU en morceaux avec un marteau. Vous le saviez probablement déjà, cependant.

Les finaliseurs devraient également fonctionner, mais il est préférable de ne pas s'en remettre au nettoyage de l'arrêt, mais de vous fier à vos crochets d'arrêt pour arrêter les choses proprement. Et, comme toujours, soyez prudent avec les deadlocks (j'ai vu beaucoup trop de crochets d'arrêt accrocher le processus entier)!

+0

Malheureusement, cela ne semble pas fonctionner sur Windows 7 (64bit). J'ai essayé d'utiliser taskill, sans le drapeau de force, et rencontre l'erreur suivante: "ERREUR: Le processus avec PID 14324 n'a pas pu être terminé Raison: Ce processus peut seulement être terminé avec force (avec l'option/F)." Fournir l'option force, "/ f", va évidemment fermer le processus instantanément. –

+0

Vous ne pouvez pas compter sur les finaliseurs en cours d'exécution. –

2

Question similaires Here

Finaliseurs en Java sont mauvais. Ils ajoutent beaucoup de frais généraux à la collecte des ordures. Évitez-les autant que possible.

Le shutdownHook ne sera appelé que lorsque la VM s'arrêtera. Je pense que c'est très bien de faire ce que tu veux.

+1

Alors shutdownHook est appelé dans TOUS les cas? Et si "tuer" le processus de shell? – Ma99uS

+0

Eh bien, pas si vous lui donnez un kill -9 :) –

0

Signaling sous Linux peut être fait avec « tuer » (homme tuer les signaux disponibles), vous auriez besoin de l'ID de processus pour le faire. (ps ax | grep java) ou quelque chose comme ça, ou stocker l'identifiant du processus lorsque le processus est créé (ceci est utilisé dans la plupart des fichiers de démarrage linux, voir /etc/init.d)

La signalisation portable peut être effectuée par intégrer un SocketServer dans votre application Java. Ce n'est pas si difficile et vous donne la liberté d'envoyer toute commande que vous voulez.

Si vous vouliez dire clauses définitives à la place des finaliseurs; ils ne sont pas exécutés lorsque System.exit() est appelé. Les finaliseurs devraient fonctionner, mais ne devraient pas vraiment faire quelque chose de plus significatif mais imprimer une instruction de débogage. Ils sont dangereux.

0

Merci pour vos réponses. Shutdown accroche les coutures comme si quelque chose fonctionnait dans mon cas. Mais j'ai aussi rencontré ce qu'on appelle les beans de surveillance et de gestion:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Cela donne de belles possibilités, pour la surveillance à distance, et la manipulation du processus Java.(A été introduit en Java 5)

46

Ok, après que toutes les possibilités que j'ai choisi de travailler avec « Java Monitoring et gestion »
Overview is here
qui vous permet de contrôler une application à partir d'un autre de manière relativement facile. Vous pouvez appeler l'application de contrôle à partir d'un script pour arrêter gracieusement l'application contrôlée avant de la supprimer.

Voici le code simplifié:

Application contrôlée:
exécuter avec les paramètres VM folowing:
-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"); 
    } 
} 
} 

application de contrôle:
terme avec l'arrêt ou début comme argument de ligne de commande

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(); 
    } 
} 
} 


Voilà. :-)

7

D'une autre manière: votre application peut ouvrir un socet de serveur et attendre qu'une information lui soit parvenue. Par exemple une chaîne avec un mot "magique" :), puis réagissez à make shutdown: System.exit(). Vous pouvez envoyer ces informations au socke en utilisant une application externe telle que telnet.

1

Voici un peu délicat, mais la solution portable:

  • Dans votre application mettre en œuvre un crochet d'arrêt
  • Lorsque vous voulez arrêter grâce à votre machine virtuelle Java, installez un Java Agent qui appelle System.exit ( en utilisant le Attach API.

J'ai implémenté l'agent Java. Il est disponible sur Github: https://github.com/everit-org/javaagent-shutdown

Description détaillée de la solution est disponible ici: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/