设置ShutdownHook并退出应用程序

时间:2012-01-17 15:53:39

标签: 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
    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会话。

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

6 个答案:

答案 0 :(得分:2)

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

sendMessage(event, getCurrentLogin());

您应该等待信号退出,例如控制台上的Ctrl + C. 只需等待锁定或信号量以避免程序完成,并且当您需要完成锁定时应该释放该锁定。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

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

我不确定操作系统是否会轻轻地杀死JVM,并且关闭钩子会执行。测试一下。

答案 3 :(得分:0)

应用程序完成时会调用shutdown hook。因此,如果您想让应用程序永远运行,您需要实现以下内容:

while (true) {
    //Your logic here
}

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

如果要实现守护程序,可以使用服务包装程序,如http://yajsw.sourceforge.nethttp://wrapper.tanukisoftware.com/

答案 4 :(得分:0)

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

您的代码在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();
        }
    }
}

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

答案 5 :(得分:-1)

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

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();
 }