1

我有以下代码:

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 会话。

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

4

6 回答 6

2

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

sendMessage(event, getCurrentLogin());

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

于 2012-01-17T16:02:51.703 回答
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";
        }
    }
于 2012-01-17T16:13:21.020 回答
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();
        }
    }
}

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

于 2012-01-17T22:33:52.023 回答
0

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

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

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

于 2012-01-17T16:04:11.973 回答
0

应用程序完成时调用关闭挂钩。所以如果你想让你的应用程序永远运行,你需要实现一些东西:

while (true) {
    //Your logic here
}

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

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

于 2012-01-17T16:04:27.910 回答
-1

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

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();
 }
于 2012-01-17T16:10:21.440 回答