我有以下代码:
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();
}