设置ShutdownHook并退出应用程序



我有以下代码:

public static void main(String[] args) {
    // login event
    String event = "login";
    System.out.printf("Handling event: %s %sn",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 %sn",event,getCurrentLogin());
                sendMessage(event, getCurrentLogin());
        }
    }));
 }

这是一个非常简单的记录用户登录和注销的程序。问题是程序在到达函数main()的末尾时退出。

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

你对后台等待登录终止有什么建议吗?

ShutdownHook是一个线程,当JVM退出并且程序在执行"sendMessage":后没有执行任何操作时执行

sendMessage(event, getCurrentLogin());

您应该等待一个信号退出,就像控制台上的Ctrl+C一样。只需等待一个锁或Semaphore以避免程序最终完成,并且该锁应该在需要完成时释放。

我在您的示例中添加了一个闩锁,以尝试使示例正常工作。不幸的是,我没有一个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 %sn", 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 %sn", 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";
        }
    }

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

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
}

如果你想写一个守护进程或调度程序,也许你需要使用一些框架作为Quartzhttp://quartz-scheduler.org

如果你想实现一个守护进程,你可以使用服务包装器http://yajsw.sourceforge.net或http://wrapper.tanukisoftware.com/

这里有一些不错的答案,但我仍然看到一些缺失的信息。

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

如果您不希望程序立即退出,那么main将不得不循环并等待某种信号。从你问题的上下文来看,我想它应该是在听sendMessage呼叫的某种响应?如果你想等待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();
        }
    }
}

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

以下是一种使用CountDownLatch保持主线程等待的方法:

public static void main(String[] args) {
    // login event
    String event = "login";
    System.out.printf("Handling event: %s %sn",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 %sn",event,getCurrentLogin());
                sendMessage(event, getCurrentLogin());
                latch.countDown();
        }
    }));
    latch.await();
 }

最新更新