如何在Eclipse启动的进程上执行shutdown hook

时间:2009-02-13 18:42:25

标签: java eclipse shutdown

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

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

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

7 个答案:

答案 0 :(得分:23)

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

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

答案 1 :(得分:12)

首先,你的申请结束还是强行结束?如果你强行结束它(通过停止按钮),这个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中从应用程序的运行配置对话框中选中/取消选中在后台启动选项。
  • 最后但并非最不重要:如果有机会,请手动调用 System.exit()。 :)

答案 2 :(得分: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'"

答案 3 :(得分:1)

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

答案 4 :(得分:1)

在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 :(得分:0)

此刻我陷入了网络圈,并没有看到我在寻找什么。 但我确实记得eclipse有一个与在同一个VM中启动应用程序相关的运行配置选项。 您是否可以在与eclipse VM相同的VM中启动Java应用程序?

但这个选项让我不知所措。

答案 6 :(得分:0)

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