0

我正在尝试让一个关闭挂钩在 java 中运行。这个钩子的目的是写入一个程序被终止的日志文件。Java 应用程序被编译成 jar 文件并使用批处理文件执行,这意味着应用程序的输出将转到 cmd.exe 窗口。当此 cmd 窗口关闭时,我希望应用程序记录它已关闭。

该应用程序旨在无限期地运行并在特定时间执行特定任务。因此,程序在“While true”循环中执行一系列检查。我不明白为什么这个钩子不会记录应用程序正在关闭!

在主要方法中,我们有:

final Thread mainThread = Thread.currentThread();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable()
{
    @Override
    public void run()
    {
        try { mainThread.join(); }
        catch (InterruptedException e) { }
        mission.log("Program Closed.", true);
    }
}
));

所有“任务”都是我的一个自定义类的实例,它进行数据记录。当您调用方法“log”时,它有一个 BufferedWriter 并调用它的 .write()、.newLine() 和 .flush() 方法。

当我杀死批处理窗口时,我似乎无法在我的日志文件中获得“程序关闭”行。我究竟做错了什么?

4

4 回答 4

3

强制杀死应用程序,即不优雅,因此JVM不知道应用程序正在退出,因此不会调用关闭挂钩。

不幸的是,没有办法(至少在 Windows 中)提供一种机制来确保始终调用挂钩。它只是可以调用的东西,但不能保证。

于 2014-01-29T16:11:41.680 回答
0

在您的进程退出之前,无法始终执行某些操作。例如,如果您将插头从墙上插座中拔出,您的计算机会立即关闭。或者,如果该进程被操作系统通过从调度程序中删除 CPU 时间来杀死它,它也没有机会。

但是,如果您删除代码

    try { mainThread.join(); }
    catch (InterruptedException e) { }

然后它将至少在某些情况下执行,例如进程的正常终止。在这里检查主线程没有意义,因为关闭钩子是由于主线程完成其工作(它退出了 main() 方法)而执行的,或者主线程将继续运行直到JVM 决定终止(如果从外部终止)。

比较如何在 Java 中优雅地处理 SIGKILL 信号的公认答案,其中包含您正在尝试做的另一个示例。

于 2014-01-29T16:11:53.760 回答
0

关闭窗口会终止进程,因此关闭挂钩将不起作用。

听起来你宁愿根本不杀死这个过程。您应该考虑使用批处理脚本以外的东西。您可以从 Windows 任务调度程序运行可执行 jar 并让它一直在后台运行 - 除非有人故意杀死 java 或发生错误。在这种情况下,您应该尝试捕获异常并以这种方式记录它们。

于 2014-01-29T16:12:22.913 回答
0

这里的每个人都是正确的——你不能在你的程序上记录一个强制停止。但是,您可能会考虑使用另一个程序来“监视”您的程序并等待它退出。然后,“观察者”程序可以记录原始程序的终止,然后自行退出。

于 2014-06-05T16:15:31.983 回答