56

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

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

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

4

7 回答 7

24

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

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);
}  
于 2009-03-11T23:37:05.390 回答
12

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 report has details about why this might not be working.

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 does execute the shutdown hooks as expected.

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#addShutdownHook do 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!)

  • Make sure the JVM does not include the -Xrs option. This has a side-effect on shutdown hooks.
  • Try launching the JVM using either the -server or -client option. 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 background option from your application's Run Configuration dialog in Eclipse.
  • Last but not least: Invoke System.exit() manually if you have the opportunity. :)
于 2009-02-18T03:24:33.167 回答
5

这是一个您可以在 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'"
于 2012-03-23T01:35:17.643 回答
2

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

现在我们需要一个外部程序将 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;
}

测试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...
于 2017-08-18T10:42:57.320 回答
1

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

于 2009-02-13T19:07:31.363 回答
0

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

但这个选项让我忘记了。

于 2009-02-18T06:29:38.900 回答
0

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

于 2015-09-25T08:37:06.240 回答