简体   繁体   English

如何优雅地停止java进程?

[英]How to stop java process gracefully?

How do I stop a Java process gracefully in Linux and Windows?如何在 Linux 和 Windows 中优雅地停止 Java 进程?

When does Runtime.getRuntime().addShutdownHook get called, and when does it not? Runtime.getRuntime().addShutdownHook什么时候被调用,什么时候不调用?

What about finalizers, do they help here?终结器呢,它们在这里有帮助吗?

Can I send some sort of signal to a Java process from a shell?我可以从 shell 向 Java 进程发送某种信号吗?

I am looking for preferably portable solutions.我正在寻找最好的便携式解决方案。

Shutdown hooks execute in all cases where the VM is not forcibly killed.关闭钩子在 VM 没有被强行杀死的所有情况下都会执行。 So, if you were to issue a "standard" kill ( SIGTERM from a kill command) then they will execute.因此,如果您要发出“标准”终止(来自SIGTERM命令的SIGTERM ),那么它们将执行。 Similarly, they will execute after calling System.exit(int) .同样,它们将在调用System.exit(int)后执行。

However a hard kill ( kill -9 or kill -SIGKILL ) then they won't execute.然而,硬杀死( kill -9kill -SIGKILL )然后他们不会执行。 Similarly (and obviously) they won't execute if you pull the power from the computer, drop it into a vat of boiling lava, or beat the CPU into pieces with a sledgehammer.类似地(并且显然),如果您从计算机上拔下电源,将其放入沸腾的熔岩桶中,或者用大锤将 CPU 打成碎片,它们就不会执行。 You probably already knew that, though.不过,您可能已经知道了。

Finalizers really should run as well, but it's best not to rely on that for shutdown cleanup, but rather rely on your shutdown hooks to stop things cleanly. Finalizers 确实也应该运行,但最好不要依赖它来进行关闭清理,而是依靠你的关闭钩子来干净地停止事情。 And, as always, be careful with deadlocks (I've seen far too many shutdown hooks hang the entire process)!而且,一如既往,要小心死锁(我见过太多的关闭钩子挂起整个过程)!

Ok, after all the possibilities I have chosen to work with "Java Monitoring and Management"好的,毕竟我选择使用“Java 监控和管理”
Overview is here 概述在这里
That allows you to control one application from another one in relatively easy way.这允许您以相对简单的方式从另一个应用程序控制一个应用程序。 You can call the controlling application from a script to stop controlled application gracefully before killing it.您可以从脚本调用控制应用程序,以在终止之前优雅地停止受控应用程序。

Here is the simplified code:这是简化的代码:

Controlled application:受控应用:
run it with the folowing VM parameters:使用以下 VM 参数运行它:
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=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");
    }
}
}

Controlling application:控制应用:
run it with the stop or start as the command line argument使用stopstart作为命令行参数运行它

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


That's it.就是这样。 :-) :-)

An another way: your application can open a server socet and wait for an information arrived to it.另一种方式:您的应用程序可以打开一个服务器 socet 并等待信息到达它。 For example a string with a "magic" word :) and then react to make shutdown: System.exit().例如一个带有“魔法”字的字符串 :) 然后做出反应以关闭:System.exit()。 You can send such information to the socke using an external application like telnet.您可以使用诸如 telnet 之类的外部应用程序将此类信息发送到 socke。

Here is a bit tricky, but portable solution:这是一个有点棘手但可移植的解决方案:

  • In your application implement a shutdown hook在您的应用程序中实现关闭挂钩
  • When you want to shut down your JVM gracefully, install a Java Agent that calls System.exit() using the Attach API .当您想要正常关闭 JVM 时,请安装一个使用Attach API调用System.exit()Java 代理

I implemented the Java Agent.我实现了 Java 代理。 It is available on Github: https://github.com/everit-org/javaagent-shutdown它在 Github 上可用: https : //github.com/everit-org/javaagent-shutdown

Detailed description about the solution is available here: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/有关解决方案的详细说明,请访问: https : //everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/

Similar Question Here类似的问题在这里

Finalizers in Java are bad. Java 中的终结器很糟糕。 They add a lot of overhead to garbage collection.它们为垃圾收集增加了大量开销。 Avoid them whenever possible.尽可能避免它们。

The shutdownHook will only get called when the VM is shutting down. shutdownHook 只会在 VM 关闭时被调用。 I think it very well may do what you want.我认为它可以很好地做你想做的事。

Signalling in Linux can be done with "kill" (man kill for the available signals), you'd need the process ID to do that. Linux 中的信令可以通过“kill”(可用信号的 man kill)来完成,您需要进程 ID 来执行此操作。 (ps ax | grep java) or something like that, or store the process id when the process gets created (this is used in most linux startup files, see /etc/init.d) (ps ax | grep java) 或类似的东西,或在进程创建时存储进程 ID(这在大多数 linux 启动文件中使用,请参阅 /etc/init.d)

Portable signalling can be done by integrating a SocketServer in your java application.可以通过在 Java 应用程序中集成 SocketServer 来实现可移植信号。 It's not that difficult and gives you the freedom to send any command you want.这并不难,让您可以自由地发送您想要的任何命令。

If you meant finally clauses in stead of finalizers;如果你的意思是 finally 子句而不是终结器; they do not get extecuted when System.exit() is called.当 System.exit() 被调用时,它们不会被执行。 Finalizers should work, but shouldn't really do anything more significant but print a debug statement.终结器应该工作,但不应该做任何更重要的事情,但打印调试语句。 They're dangerous.他们很危险。

Thanks for you answers.谢谢你的回答。 Shutdown hooks seams like something that would work in my case.关机钩接缝就像在我的情况下有用的东西。 But I also bumped into the thing called Monitoring and Management beans:但我也碰到了一个叫做监控和管理 bean 的东西:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
That gives some nice possibilities, for remote monitoring, and manipulation of the java process.这提供了一些很好的可能性,用于远程监控和 Java 进程的操作。 (Was introduced in Java 5) (在 Java 5 中引入)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM