【问题标题】:How to get shutdown hook to execute on a process launched from Eclipse如何让关闭挂钩在从 Eclipse 启动的进程上执行
【发布时间】:2010-10-07 12:36:10
【问题描述】:

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

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

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

【问题讨论】:

  • 不要在 Eclipse 中运行您的应用程序?
  • 我认为@mattb 的建议很好,因为大多数程序在某些时候应该在 IDE 之外运行。顺便说一句,IntelliJ IDEA 有一个按钮:stackoverflow.com/questions/4727536
  • @TimBüthe,很好,但在我们进行快速代码-测试-调试-代码-测试-调试周期时没有用...

标签: java eclipse shutdown


【解决方案1】:

我在主要方法结束时使用了以下技巧来解决问题:

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

【讨论】:

  • 注意:必须在运行配置中手动添加环境变量“RUNNING_IN_ECLIPSE”,并将值设置为TRUE。
  • 或者你可以只做没有 if/else 的行,仅用于调试目的。
  • 如果我们想在一个正在运行的控制台应用上测试“关机”,这个解决方案就不起作用了。
【解决方案2】:

首先,您的应用程序是结束还是强制结束?如果您是强制结束它(通过停止按钮),这个Eclipse bug report 详细说明了为什么这可能不起作用。

否则,您可能会认为这是 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." );
    }
}

Runtime#addShutdownHook 的 Javadocs 确实提到,当 JVM 中止而不是正常退出时,关闭挂钩不会运行,因此,您的假设可能是正确的。话虽如此,这里有一些事情可以尝试。再次抱歉,我无法提前确认这些信息——这里没有 Windows。 (幸好!)

  • 确保 JVM 不包含 -Xrs 选项。这在关闭挂钩上有一个side-effect
  • 尝试使用 -server-client 选项启动 JVM。根据我的经验,选择 VM 模式会影响边缘情况的行为。 (尤其是在线程方面——至少在 Mac 上。)
  • 您是否在分析器或类似工具下启动您的应用程序?加载任何本机库?
  • 您是否遇到了一些致命错误并遗漏了它?例如,OutOfMemoryError 等?
  • 尝试在 Eclipse 中应用程序的 Run Configuration 对话框中选中/取消选中 Launch in background 选项。
  • 最后但同样重要的是:如果有机会,请手动调用 System.exit()。 :)

【讨论】:

  • 你怎么知道要搜索 -Xrs 选项?
【解决方案3】:

这是一个可以在 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 $1}')
echo "Launcher PID $LAUNCHER_PID"

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

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

# 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'"

【讨论】:

  • 嗯,不过杀了就等于强行停了吧?因此,关闭挂钩不会运行。
  • @Pacerier 取决于您使用的信号。默认值为 TERM,它将运行关闭挂钩。 kill -9 不会运行关闭挂钩。更多信息:superuser.com/questions/107543/…
【解决方案4】:

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

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

#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;
}

测试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);
    }

}

终止它:

C:\>killsoft.exe 10520

在 Eclipse 中测试程序输出:

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

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

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

      但我没有想到这个选项。

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-10-21
          • 2011-04-26
          • 1970-01-01
          • 2020-05-18
          • 1970-01-01
          • 1970-01-01
          • 2015-12-27
          相关资源
          最近更新 更多