Comment puis-je arrêter un processus Java dans Linux et Windows?)
Quand est-ce que Runtime.getRuntime().addShutdownHook
est appelé et quand ne le fait-il pas?
Qu'en est-il des finaliseurs, aident-ils ici?
Puis-je envoyer une sorte de signal à un processus Java à partir d'un shell?)?
Je recherche de préférence des solutions portables.
Les crochets d'arrêt s'exécutent dans tous les cas où le VM n'est pas tué de force. Donc, si vous devez émettre un kill "standard" (SIGTERM
à partir d'une commande de kill), ils seront alors De même, ils s'exécuteront après avoir appelé System.exit(int)
.
Cependant, une tuerie dure (kill -9
ou kill -SIGKILL
) alors ils ne seront pas exécutés. De même (et évidemment), ils ne fonctionneront pas si vous retirez l'alimentation de l'ordinateur, si vous le déposez dans une cuve de lave en ébullition ou si vous battez le processeur en plusieurs morceaux avec un marteau pilon. Vous le saviez probablement déjà, cependant.
Les finaliseurs devraient vraiment fonctionner aussi bien, mais il vaut mieux ne pas compter sur cela pour le nettoyage après arrêt, mais plutôt sur vos crochets d'arrêt pour arrêter les choses proprement. Et, comme toujours, faites attention aux impasses (j'ai vu beaucoup trop de crochets d'arrêt pendant tout le processus)!
Ok, après toutes les possibilités que j'ai choisies de travailler avec "Java Monitoring and Management"
la vue d'ensemble est ici
Cela vous permet de contrôler une application d’une autre de manière relativement simple. Vous pouvez appeler l'application de contrôle à partir d'un script pour arrêter l'application contrôlée avant de la tuer.
Voici le code simplifié:
Application contrôlée:
exécutez-le avec les paramètres suivants 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");
}
}
}
Application de contrôle:
l'exécutez avec le stop ou start 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();
}
}
}
C'est ça. :-)
Une autre façon: 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" :) et réagit pour faire shutdown: System.exit (). Vous pouvez envoyer ces informations à la chaussette à l'aide d'une application externe telle que Telnet.
Question similaire ici
Les finaliseurs dans Java sont incorrects. Ils alourdissent considérablement le ramassage des ordures. Évitez-les autant que possible.
ShutdownHook ne sera appelé que lorsque VM est en train de s’arrêter. Je pense qu’il peut très bien faire ce que vous voulez.
Voici une solution un peu délicate mais portable:
J'ai implémenté l'agent Java. Il est disponible sur Github: https://github.com/everit-org/javaagent-shutdown
Une description détaillée de la solution est disponible ici: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/
Merci pour vos réponses. La fermeture des crochets ressemble à quelque chose qui fonctionnerait dans mon cas. Mais je suis aussi tombé sur ce qu'on appelle les beans Monitoring and Management:
http://Java.Sun.com/j2se/1.5.0/docs/guide/management/overview.html
Cela donne quelques possibilités intéressantes pour la surveillance à distance et la manipulation du processus Java. (A été introduit dans Java 5)
La signalisation sous Linux peut être effectuée avec "kill" (man kill pour les signaux disponibles), vous aurez besoin de l'ID de processus pour le faire. (ps ax | grep Java) ou quelque chose comme ça, ou stocke l'identifiant du processus lorsque le processus est créé (utilisé dans la plupart des fichiers de démarrage de Linux, voir /etc/init.d)
La signalisation portable peut être effectuée en intégrant un SocketServer dans votre application Java. Ce n'est pas si difficile et vous donne la liberté d'envoyer toute commande de votre choix.
Si vous vouliez enfin parler de clauses au lieu de finaliseurs; ils ne sont pas exécutés lorsque System.exit () est appelé. Les finaliseurs devraient fonctionner, mais ne devraient rien faire de plus important que d’imprimer une déclaration de débogage. Ils sont dangereux.