如何让关闭挂钩在从 Eclipse 启动的进程上执行
Posted
技术标签:
【中文标题】如何让关闭挂钩在从 Eclipse 启动的进程上执行【英文标题】:How to get shutdown hook to execute on a process launched from 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 有一个按钮:***.com/questions/4727536。 @TimBüthe,很好,但在我们进行快速代码-测试-调试-代码-测试-调试周期时没有用... 【参考方案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 发送到带有隐藏控制台的进程。我找到了提示here 和here。我们的程序附加到所需进程的控制台并发送控制台事件。
#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 结果
【讨论】:
以上是关于如何让关闭挂钩在从 Eclipse 启动的进程上执行的主要内容,如果未能解决你的问题,请参考以下文章