首页 > 解决方案 > Java 程序如何检测到 MacOS 机器正在关闭?

问题描述

我有一个 Java 应用程序,每当我启动机器时,我想在我的 Mac 上启动它。每当机器关闭时,应用程序都应该正常关闭。

我在 main 方法中添加了一个关闭钩子:

Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(scheduler)));

ShutdownHook类看起来像这样:

public class ShutdownHook implements  Runnable {
    private final static Logger LOGGER = LoggerFactory.getLogger("Shutdown Hook");
    private final Scheduler scheduler;

    public ShutdownHook(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    @Override
    public void run() {
        LOGGER.debug("Starting to shot down the application");
        try {
            scheduler.shutdown();
        } catch (final SchedulerException e) {
           LOGGER.error("An error occurred while trying to shut down the scheduler", e);
        }
        LOGGER.info("Exiting the shutdown hook");
    }
}

然后我将应用程序构建到一个可执行的 JAR 中,并将其添加到“登录项”列表中。

该应用程序在我登录时启动。

但是,机器关闭时不会执行关闭挂钩。

如何确保当我使用下面显示的菜单项关闭机器时,正在运行的 Java 应用程序检测到机器正在关闭?

更新1:

据我了解,修复错误的一种方法是使用launchd启动 Java 程序。我在下面写了plist文件。

下一个问题是如何确保launchd运行该plist文件中描述的应用程序?

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>ExitTimeOut</key>
    <integer>300</integer>
    <key>StandardErrorPath</key>
    <string>/Users/XXXXXX/sw/wordcounter-daemon/error</string>
    <key>Label</key>
    <string>com.dpisarenko.wordcounterdaemon</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/java</string>
        <string>-jar</string>
        <string>/Users/XXXXXXX/sw/wordcounter-daemon/wordcounter-daemon-0.1-jar-with-dependencies.jar</string>
    </array>
</dict>
</plist>

标签: javamacosdaemon

解决方案


通常 Unix 风格的系统会分两步关闭一个守护进程:

  1. SIGTERM信号发送到进程

  2. SIGKILL如果进程在点 1 后 X 秒后仍运行,则向进程发送信号

这个答案解释了如何ExitTimeOut在 MacOS 上配置控制这两个信号之间时间的值。

非守护进程的行为可能不同,这可能是您的进程未执行 JVM 关闭挂钩的原因。JVM 可能接收到SIGKILL并且通过设计用户空间进程无法处理此信号。您可能希望将您的进程转换为守护进程。


推荐阅读