如何优雅地停止Java进程?

2022-08-31 11:08:09

如何在 Linux 和 Windows 中优雅地停止 Java 进程?

什么时候被叫到,什么时候不被叫到?Runtime.getRuntime().addShutdownHook

那么终结者呢,它们在这里有帮助吗?

我可以从shell向Java进程发送某种信号吗?

我正在寻找更可取的便携式解决方案。


答案 1

关闭挂钩在未强制终止 VM 的所有情况下执行。因此,如果您要发出“标准”杀戮(从杀戮命令),那么它们将执行。同样,它们将在调用 后执行。SIGTERMSystem.exit(int)

然而,硬杀(或)然后他们不会执行。同样(显然),如果你从计算机中拔出电源,将其放入沸腾的熔岩桶中,或者用大锤将CPU打成碎片,它们也不会执行。不过,您可能已经知道这一点。kill -9kill -SIGKILL

终结器确实也应该运行,但最好不要依赖它来清理关闭,而是依靠关闭钩子来干净利落地停止事情。而且,与往常一样,要小心死锁(我已经看到太多的关机钩子挂起了整个过程)!


答案 2

好吧,在我选择使用“Java监视和管理”
的所有可能性之后,概述在这里
,它允许您以相对简单的方式从另一个应用程序控制一个应用程序。您可以从脚本中调用控制应用程序,以便在终止受控应用程序之前正常停止它。

下面是简化的代码:

受控应用程序:
使用 folowing 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");
    }
}
}

控制应用程序:
停止启动作为命令行参数运行它

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


就是这样。:-)


推荐