Java 如何让关闭钩子在从 Eclipse 启动的进程上执行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/547169/
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-11 16:04:55  来源:igfitidea点击:

How to get shutdown hook to execute on a process launched from Eclipse

javaeclipseshutdown

提问by

I have a shutdown hook in my application (created using Runtime.getRuntime().addShutdownHook). However if I launch the application from within Eclipse, when it is shut-down the shutdown hook doesn't execute.

我的应用程序中有一个关闭挂钩(使用 创建Runtime.getRuntime().addShutdownHook)。但是,如果我从 Eclipse 中启动应用程序,当它关闭时,关闭挂钩不会执行。

I think this is because Eclipse sends the equivalent of a force-kill signal to the process, which doesn't cause the shut-down hook to execute (equivalent of taskkill /F on Windows or kill -p on Linux), though I'm not absolutely sure.

我认为这是因为 Eclipse 向进程发送了相当于强制终止信号的信号,这不会导致关闭挂钩执行(相当于 Windows 上的 taskkill /F 或 Linux 上的 kill -p),尽管我我不是很确定。

Does anyone know how to get around this? I'm running Windows (Vista), and I've a feeling it may be a Windows-specific issue, but I'm not sure.

有谁知道如何解决这个问题?我正在运行 Windows (Vista),我感觉这可能是 Windows 特定的问题,但我不确定。

回答by Javamann

I'm not sure how to fix this but IntelliJ added a separate button to their 'Run' dialog which will shutdown the VM in a way that calls the Shutdown Hooks. Their debugger does not have this feature.

我不确定如何解决这个问题,但 IntelliJ 在他们的“运行”对话框中添加了一个单独的按钮,该按钮将以调用关闭挂钩的方式关闭虚拟机。他们的调试器没有这个功能。

回答by JLR

First off, is your application ending or are you forcibly ending it? If you are forcibly ending it (via the stop button), this Eclipse bug reporthas details about why this might not be working.

首先,您的申请是结束还是强行结束?如果您强行结束它(通过停止按钮),这个Eclipse 错误报告详细说明了为什么这可能不起作用。

Failing that, you may be correct about this being Windows-specific behavior. I'm on a Mac so I can't confirm, sorry. However, I can tell you that the following test program doesexecute the shutdown hooks as expected.

否则,您可能认为这是 Windows 特定的行为是正确的。我在 Mac 上,所以我无法确认,抱歉。但是,我可以告诉您,以下测试程序确实按预期执行了关闭挂钩。

public class MyShutdownHook
{
    public static void main( String[] args )
    {
        System.out.println( "Entering main." );

        Runtime.getRuntime().addShutdownHook( 
            new Thread(
                new Runnable() {
                    public void run() {
                        System.out.println( "Shutdown hook ran." );
                    }   
                }
            )
        );

        System.out.println( "Exiting main." );
    }
}

The Javadocs for Runtime#addShutdownHookdo mention that shutdown hooks do not run when the JVM is aborted, not exited normally, so again, you are probably correct in your assumptions. That being said, here are some things to try. Again, sorry I can't confirm these ahead of time -- no Windows here. (Blessedly!)

Runtime#addShutdownHook的 Javadocs确实提到关闭钩子在 JVM 中止时不会运行,不会正常退出,所以同样,您的假设可能是正确的。话虽如此,这里有一些事情可以尝试。再次,抱歉我不能提前确认这些——这里没有 Windows。(有福了!)

  • Make sure the JVM does not include the -Xrsoption. This has a side-effecton shutdown hooks.
  • Try launching the JVM using either the -serveror -clientoption. It's been my experience that edge-case behavior can be effected by the choice of VM mode. (Especially with regard to threading -- at least on Mac.)
  • Are you launching your app under a profiler or the like? Loading any native libraries?
  • Are you getting some fatal error and missing it? E.g., OutOfMemoryError or the like?
  • Try checking/unchecking the Launch in backgroundoption from your application's Run Configurationdialog in Eclipse.
  • Last but not least: Invoke System.exit()manually if you have the opportunity. :)
  • 确保 JVM 不包括-Xrs选项。这对关闭钩子有副作用
  • 尝试使用-server-client选项启动 JVM 。根据我的经验,边缘情况的行为会受到 VM 模式选择的影响。(特别是关于线程——至少在 Mac 上。)
  • 您是在分析器或类似工具下启动您的应用程序吗?加载任何本地库?
  • 您是否遇到了一些致命错误并错过了它?例如,OutOfMemoryError 之类的?
  • 尝试从Eclipse 中应用程序的运行配置对话框中选中/取消选中Launch in background选项。
  • 最后但并非最不重要的一点:如果有机会,请手动调用System.exit()。:)

回答by guyumu

I'm stuck in websphere at the moment, and don't see what I'm looking for. But I do remember eclipse having a run configuration option related to launching the application in the same VM. Is it possible your launching your java application in the same VM as the eclipse VM?

我目前被困在 websphere 中,看不到我在找什么。但我确实记得 eclipse 有一个与在同一 VM 中启动应用程序相关的运行配置选项。是否可以在与 eclipse VM 相同的 VM 中启动 Java 应用程序?

But the option slips my mind.

但是这个选项让我忘记了。

回答by guyumu

I used the following hack at the end of my main method to get around the problem:

我在主要方法的末尾使用了以下技巧来解决这个问题:

if (Boolean.parseBoolean(System.getenv("RUNNING_IN_ECLIPSE"))) {
    System.out.println("You're using Eclipse; click in this console and " +
            "press ENTER to call System.exit() and run the shutdown routine.");
    try {
        System.in.read();
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.exit(0);
}  

回答by Jason Axelson

Here's a script that you can run outside of eclipse to list the available processes running under Eclipse that you could kill.

这是一个脚本,您可以在 eclipse 之外运行该脚本,以列出在 Eclipse 下运行的可用进程,您可以杀死它。

#!/bin/bash
set -o nounset                              # Treat unset variables as an error

PROCESSES=$(ps axo pid,ppid,command)

# Find eclipse launcher PID
LAUNCHER_PID=$(echo "$PROCESSES" | grep "/usr/lib/eclipse/eclipse" |grep -v "launcher"|awk '{print }')
echo "Launcher PID $LAUNCHER_PID"

# Find eclipse PID
ECLIPSE_PID=$(echo "$PROCESSES" | egrep "[[:digit:]]* $LAUNCHER_PID " | awk '{print }')
echo "Eclipse PID $ECLIPSE_PID"

# Find running eclipse sub-process PIDs
SUB_PROCESS=$(echo "$PROCESSES" | egrep "[[:digit:]]* $ECLIPSE_PID " | awk '{print }')

# List processes
echo
for PROCESS in $SUB_PROCESS; do
    DRIVER=$(ps --no-headers o pid,ppid,command $PROCESS | awk '{print $NF}')
    echo "$PROCESS $DRIVER"
done

echo "Kill a process using: 'kill -SIGTERM $PID'"

回答by Shashank

Sairam is right here, By calling System.exit(0)we can terminate eclipse JVM and can see Shutdown hook results

Sairam 就在这里,通过调用System.exit(0)我们可以终止 eclipse JVM 并可以看到 Shutdown hook 结果

回答by basin

On Windows to gracefully stop a java application in a standard way you need to send Ctrl+ Cto it. This only works with console apps, but Eclipse uses javaw.exeinstead of java.exe. To solve this open the launch configuration, JRE tab and select "Alternative JRE:". The "Java executable" group box appears and allows to enter the alternate executable "java".

在 Windows 上,要以标准方式优雅地停止 Java 应用程序,您需要向它发送Ctrl+ C。这仅与控制台应用程序的工作,但Eclipse使用javaw.exe的替代java.exe。要解决此问题,请打开启动配置、JRE 选项卡并选择“Alternative JRE:”。“Java 可执行文件”组框出现并允许输入替代的可执行文件“java”。

Now we need an external program to send Ctrl-C to a process with a hidden console. I found hints hereand here. Our program attaches to the console of the desired process and sends the console event.

现在我们需要一个外部程序将 Ctrl-C 发送到一个带有隐藏控制台的进程。我在这里这里找到了提示。我们的程序附加到所需进程的控制台并发送控制台事件。

#include <stdio.h>
#include <windows.h>

int main(int argc, char* argv[])
{
    if (argc == 2) {
        unsigned pid = 0;
        if (sscanf_s(argv[1], "%u", &pid) == 1) {
            FreeConsole(); // AttachConsole will fail if we don't detach from current console
            if (AttachConsole(pid)) {
                //Disable Ctrl-C handling for our program
                SetConsoleCtrlHandler(NULL, TRUE);
                GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
                return 0;
            }
        }
    }

    return 1;
}

Test java program:

测试java程序:

public class Shuthook {

    public static void main(final String[] args) throws Exception {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("Shutting down...");
            }
        });

        String sPid = ManagementFactory.getRuntimeMXBean().getName();
        sPid = sPid.substring(0, sPid.indexOf('@'));

        System.out.println("pid: " + sPid);
        System.out.println("Sleeping...");
        Thread.sleep(1000000);
    }

}

Terminating it:

终止它:

C:\>killsoft.exe 10520

Test program output in Eclipse:

Eclipse 中的测试程序输出:

pid: 10520
Sleeping...
Shutting down...