Linux 如何优雅地停止java进程?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/191215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:35:26  来源:igfitidea点击:

How to stop java process gracefully?

javalinuxwindowsshellprocess

提问by Ma99uS

How do I stop a Java process gracefully in Linux and Windows?

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

When does Runtime.getRuntime().addShutdownHookget 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.

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

采纳答案by jsight

Shutdown hooks execute in all cases where the VM is not forcibly killed. So, if you were to issue a "standard" kill (SIGTERMfrom a kill command) then they will execute. Similarly, they will execute after calling System.exit(int).

关闭钩子在 VM 没有被强行杀死的所有情况下都会执行。因此,如果您要发出“标准”kill(SIGTERM来自 kill 命令),那么它们将执行。同样,它们将在调用后执行System.exit(int)

However a hard kill (kill -9or kill -SIGKILL) then they won't execute. 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. You probably already knew that, though.

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

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. And, as always, be careful with deadlocks (I've seen far too many shutdown hooks hang the entire process)!

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

回答by Steve g

Similar Question Here

类似的问题在这里

Finalizers in Java are bad. They add a lot of overhead to garbage collection. Avoid them whenever possible.

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

The shutdownHook will only get called when the VM is shutting down. I think it very well may do what you want.

shutdownHook 只会在 VM 关闭时被调用。我认为它可以很好地做你想做的事。

回答by extraneon

Signalling in Linux can be done with "kill" (man kill for the available signals), you'd need the process ID to do that. (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)

Linux 中的信令可以通过“kill”(可用信号的 man kill)来完成,您需要进程 ID 来执行此操作。(ps ax | grep java) 或类似的东西,或在进程创建时存储进程 ID(这在大多数 linux 启动文件中使用,请参阅 /etc/init.d)

Portable signalling can be done by integrating a SocketServer in your java application. It's not that difficult and gives you the freedom to send any command you want.

可以通过在 Java 应用程序中集成 SocketServer 来实现可移植信号。这并不难,让您可以自由地发送您想要的任何命令。

If you meant finally clauses in stead of finalizers; they do not get extecuted when System.exit() is called. Finalizers should work, but shouldn't really do anything more significant but print a debug statement. They're dangerous.

如果你的意思是 finally 子句而不是终结器;当 System.exit() 被调用时,它们不会被执行。终结器应该工作,但不应该做任何更重要的事情,但打印调试语句。他们很危险。

回答by Ma99uS

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:
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. (Was introduced in Java 5)

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

回答by Ma99uS

Ok, after all the possibilities I have chosen to work with "Java Monitoring and Management"
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.

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

Here is the simplified code:

这是简化的代码:

Controlled application:
run it with the folowing VM parameters:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

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

Controlling application:
run it with the stopor startas 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. :-)


就是这样。:-)

回答by Ma99uS

An another way: your application can open a server socet and wait for an information arrived to it. For example a string with a "magic" word :) and then react to make shutdown: System.exit(). You can send such information to the socke using an external application like telnet.

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

回答by Balazs Zsoldos

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 Agentthat calls System.exit()using the Attach API.
  • 在您的应用程序中实现关闭挂钩
  • 当您想要正常关闭 JVM 时,请安装一个使用Attach API调用System.exit()Java 代理

I implemented the Java Agent. It is available on Github: https://github.com/everit-org/javaagent-shutdown

我实现了 Java 代理。它在 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/