Como parar o processo java graciosamente?

Como faço para parar um processo Java normalmente no Linux e no Windows?

Quando o Runtime.getRuntime().addShutdownHook é chamado e quando não é?

E quanto aos finalizadores, eles ajudam aqui?

Posso enviar algum tipo de sinal para um processo Java a partir de um shell?

Eu estou procurando soluções de preferência portáteis.

   

Os ganchos de desligamento são executados em todos os casos em que a VM não é forçada a ser morta. Então, se você emitir um kill “padrão” ( SIGTERM de um comando kill), eles serão executados. Da mesma forma, eles serão executados após chamar System.exit(int) .

No entanto, uma matança difícil ( kill -9 ou kill -SIGKILL ) não será executada. Da mesma forma (e obviamente) eles não serão executados se você puxar a energia do computador, soltá-la em um tanque de lava fervente ou bater a CPU em pedaços com uma marreta. Você provavelmente já sabia disso, no entanto.

Os finalizadores também devem ser executados, mas é melhor não confiar nisso para a limpeza do desligamento, mas sim confiar em seus ganchos de desligamento para parar as coisas de maneira limpa. E, como sempre, tenha cuidado com deadlocks (eu vi muitos ganchos de desligamento pendurarem todo o processo)!

Ok, depois de todas as possibilidades que escolhi para trabalhar com “Java Monitoring and Management”
A visão geral está aqui
Isso permite que você controle um aplicativo de outro de maneira relativamente fácil. Você pode chamar o aplicativo de controle de um script para parar o aplicativo controlado normalmente antes de eliminá-lo.

Aqui está o código simplificado:

Aplicação controlada:
execute-o com os seguintes parâmetros da 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"); } } } 

Aplicativo de controle:
executá-lo com o stop ou iniciar como o argumento da linha 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(); } } } 

É isso aí. 🙂

De outra maneira: seu aplicativo pode abrir um servidor e esperar que uma informação chegue a ele. Por exemplo, uma string com uma palavra “mágica” 🙂 e depois reagir para fazer o desligamento: System.exit (). Você pode enviar essas informações para o socke usando um aplicativo externo como o telnet.

Pergunta semelhante aqui

Finalizadores em Java são ruins. Eles adicionam muita sobrecarga à garbage collection. Evite-os sempre que possível.

O shutdownHook só será chamado quando a VM estiver sendo encerrada. Eu acho que muito bem pode fazer o que quiser.

Aqui está uma solução um pouco complicada, mas portátil:

  • Em seu aplicativo, implemente um gancho de desligamento
  • Quando você deseja encerrar sua JVM normalmente, instale um Agente Java que chame System.exit () usando a API Attach .

Eu implementei o agente Java. Está disponível no Github: https://github.com/everit-org/javaagent-shutdown

A descrição detalhada sobre a solução está disponível aqui: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/

Sinalização no Linux pode ser feita com “kill” (man kill para os sinais disponíveis), você precisaria do ID do processo para fazer isso. (ps ax | grep java) ou algo parecido, ou armazene o id do processo quando o processo é criado (isto é usado na maioria dos arquivos de boot do linux, veja /etc/init.d)

A sinalização portátil pode ser feita integrando um SocketServer em seu aplicativo java. Não é tão difícil e lhe dá a liberdade de enviar qualquer comando que você quiser.

Se você quis dizer finalmente cláusulas em vez de finalizadores; eles não são extintos quando System.exit () é chamado. Os finalizadores devem funcionar, mas não devem fazer nada mais significativo, mas imprimir uma declaração de debugging. Eles são perigosos.

Obrigado por suas respostas. O desligamento prende as costuras como algo que funcionaria no meu caso. Mas eu também esbarrei na coisa chamada Monitoring and Management beans:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Isso dá algumas boas possibilidades, para monitoramento remoto e manipulação do processo java. (Foi introduzido no Java 5)