如何在Linux和Windows中优雅地停止Java进程?
何时Runtime.getRuntime().addShutdownHook
被召唤,什么时候不召唤?
终结者怎么样,他们在这里有帮助吗?
我可以从shell向Java进程发送某种信号吗?
我正在寻找最好的便携式解决方案.
在未强制终止VM的所有情况下,执行关闭挂钩.因此,如果您要发出"标准"kill(SIGTERM
来自kill命令),那么它们将执行.同样,他们会在打电话后执行System.exit(int)
.
然而,硬杀(kill -9
或kill -SIGKILL
)然后他们将不会执行.同样(显然)如果你从计算机上取下电源,将它放入一桶沸腾的熔岩中,或者用大锤将CPU打成碎片,它们就不会执行.不过你可能已经知道了.
终结器确实应该运行,但最好不要依赖它来进行关机清理,而是依靠你的关闭钩子来干净地停止事情.并且,像往常一样,小心死锁(我已经看到太多关闭挂钩挂起整个过程)!
好吧,在我选择使用"Java监控和管理"
概述之后的所有可能性之后,
这允许您以相对简单的方式从另一个应用程序控制一个应用程序.您可以从脚本中调用控制应用程序,以便在杀死它之前正常地停止受控应用程序.
这是简化的代码:
受控应用程序:
使用以下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"); } } }
控制应用程序:
使用stop或start作为命令行参数运行它
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(); } } }
而已.:-)
另一种方式:您的应用程序可以打开服务器socet并等待到达它的信息.例如,一个带有"魔术"单词的字符串:)然后做出反应以进行关闭:System.exit().您可以使用telnet等外部应用程序将此类信息发送到socke.