Java 设置关闭钩子并退出应用程序

Java 设置关闭钩子并退出应用程序,java,login,event-handling,system-shutdown,shutdown-hook,Java,Login,Event Handling,System Shutdown,Shutdown Hook,我有以下代码: public static void main(String[] args) { // login event String event = "login"; System.out.printf("Handling event: %s %s\n",event,getCurrentLogin()); sendMessage(event, getCurrentLogin()); // logout or shutdown event

我有以下代码:

public static void main(String[] args) {

    // login event
    String event = "login";
    System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
    sendMessage(event, getCurrentLogin());

    // logout or shutdown event
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
                String event = "logout";
                System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
                sendMessage(event, getCurrentLogin());
        }
    }));
 }
这是一个非常简单的程序,用于记录用户的登录和注销。问题是程序在到达函数main()的末尾时退出

我是否正确使用关闭事件挂钩? 我不想创建一个复杂的windows服务,它必须是一个非常简单的应用程序,因为它将用于远程连接的windows会话


您是否有任何关于后台等待登录终止的建议?

关闭钩子是一个线程,在JVM退出时执行,并且在您执行“sendMessage”后程序不执行任何操作:

您应该等待退出信号,如控制台上的Ctrl+C。
只要等待一个锁或信号量来避免程序终止,当您需要完成它时,应该释放该锁。

如果我理解正确,您希望无限期地等待,直到操作系统停止您的程序,对吗?如果是这样,您需要至少运行一个守护进程线程:

public static void main(String[] args) throws InterruptedException {
    //...
    final Object o = new Object();
    synchronized(o) {
        while(true) {
            o.wait();
        }
    }
}

不过,我不确定操作系统是否会足够温和地杀死JVM,也不确定关闭挂钩是否会执行。测试它。

当应用程序完成时,将调用关闭挂钩。因此,如果您想让应用程序永远运行,您需要实现以下功能:

while (true) {
    //Your logic here
}
如果您想编写守护进程或调度程序,可能需要使用一些框架


如果要实现守护程序,可以使用服务包装器,如或,这里有一种方法使用,使主线程保持等待:

public static void main(String[] args) {

    // login event
    String event = "login";
    System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
    sendMessage(event, getCurrentLogin());

    final CountDownLatch latch = new CountDownLatch(1);

    // logout or shutdown event
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
                String event = "logout";
                System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
                sendMessage(event, getCurrentLogin());
                latch.countDown();
        }
    }));

    latch.await();
 }

我在您的示例中添加了一个闩锁,以尝试使示例正常工作。不幸的是,我没有一个IDE来测试,但这应该足以给出一个想法

编辑:下面的示例将打印登录和注销

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

    public class Test {
        public static void main(String[] args) throws Exception {

            // login event
            String event = "login";
            System.out.printf("Handling event: %s %s\n", event, getCurrentLogin());
            sendMessage(event, getCurrentLogin());
            final CountDownLatch latch = new CountDownLatch(1);

            // logout or shutdown event
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    String event = "logout";
                    System.out.printf("Handling event: %s %s\n", event, getCurrentLogin());
                    sendMessage(event, getCurrentLogin());
                    latch.countDown();
                }
            }));
            latch.await(2, TimeUnit.SECONDS);
        }

        private static void sendMessage(String event, Object currentLogin) {
        }

        private static Object getCurrentLogin() {
            return "X";
        }
    }

这里有一些很好的答案,但我仍然看到一些缺失的信息

您的代码在
main
中注册一个关机挂钩,然后main到达末尾并返回。当最后一个非守护进程线程退出时,将调用关闭挂钩。我怀疑main是唯一的非守护进程线程,因此当
main
退出时,会立即调用钩子

如果不希望程序立即退出,则必须循环并等待某种信号。从你的问题的上下文来看,我想它应该是在听
sendMessage
call的某种回应?如果您想等待control-c,那么我喜欢@JB Nizet的答案:

public static void main(String[] args) throws InterruptedException {
    ...
    Runtime.getRuntime().addShutdownHook(...);
    // wait until control-c is called
    final Object o = new Object();
    synchronized(o) {
        while(true) {
            o.wait();
        }
    }
}

您希望在注册关闭挂钩后开始等待,以便执行关闭代码。

这不会编译,因为锁存不是最终的。请看我的答案,以找到正确的方法;)更正了它,我没有给出一个免责声明,这只是给出一个想法,而不是一个有效的解决方案。我没有看到InterruptedException的处理?
public static void main(String[] args) throws InterruptedException {
    ...
    Runtime.getRuntime().addShutdownHook(...);
    // wait until control-c is called
    final Object o = new Object();
    synchronized(o) {
        while(true) {
            o.wait();
        }
    }
}