如何优雅地停止java进程?

时间:2008-10-10 13:17:36

标签: java linux windows shell process

如何在Linux和Windows中正常停止Java进程?

何时调用Runtime.getRuntime().addShutdownHook,什么时候不调用?

终结者怎么样,他们在这里有帮助吗?

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

我正在寻找最好的便携式解决方案。

7 个答案:

答案 0 :(得分:78)

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

然而,硬杀死(kill -9kill -SIGKILL)则不会执行。同样(显然)如果你从计算机上取下电源,将它放入一桶沸腾的熔岩中,或者用大锤将CPU打成碎片,它们就不会执行。不过你可能已经知道了。

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

答案 1 :(得分:47)

好的,在我选择使用“Java监控和管理”的所有可能性之后 Overview is here
这允许您以相对简单的方式从另一个应用程序控制一个应用程序。您可以从脚本中调用控制应用程序,在杀死它之前优雅地停止受控应用程序。

以下是简化代码:

受控应用程序:
使用以下VM参数运行它:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port = 9999
-Dcom.sun.management.jmxremote.authenticate =假
-Dcom.sun.management.jmxremote.ssl =假

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


而已。 :-)

答案 2 :(得分:7)

另一种方式:您的应用程序可以打开服务器socet并等待到达它的信息。例如,一个带有“魔术”单词的字符串:)然后做出反应以进行关闭:System.exit()。您可以使用telnet等外部应用程序将此类信息发送到socke。

答案 3 :(得分:2)

类似问题Here

Java中的终结器很糟糕。它们为垃圾收集增加了很多开销。尽可能避免使用它们。

只有在VM关闭时才会调用shutdownHook。我认为很可能做你想做的事。

答案 4 :(得分:2)

这是一个有点棘手但又便携的解决方案:

  • 在您的应用程序中实现一个关闭挂钩
  • 当您想要正常关闭JVM时,请使用Java Agent安装一个调用 System.exit()Attach API

我实现了Java代理。它可以在Github上找到:https://github.com/everit-org/javaagent-shutdown

有关该解决方案的详细说明,请访问:https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/

答案 5 :(得分:0)

Linux中的信令可以通过“kill”完成(man kill for available signals),你需要进程ID来做到这一点。 (ps ax | grep java)或类似的东西,或者在创建进程时存储进程id(这在大多数linux启动文件中使用,请参阅/etc/init.d)

可以通过在Java应用程序中集成SocketServer来完成便携式信令。这并不困难,让您可以自由发送任何命令。

如果你的意思是最终的条款而不是终结者;调用System.exit()时,它们不会被扩展。 终结器应该可以工作,但不应该做任何更重要的事情,但打印调试语句。他们很危险。

答案 6 :(得分:0)

谢谢你的回答。关闭钩子接缝就像在我的情况下工作的东西。 但我也碰到了监控和管理豆子的事情:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
这给了一些很好的可能性,用于远程监控和java进程的操作。 (在Java 5中引入)