我有一个程序,不断地轮询数据库中某个字段的值是否发生变化。它在后台运行,目前使用while(true)和sleep()方法设置时间间隔。我想知道这是否是一种好的做法?还有,是否有更有效的实现方式?该程序需要始终运行。
因此,停止程序的唯一方法是对进程ID执行kill命令。该程序可能正在进行JDBC调用。如何更优雅地终止程序?我知道最好的选择是通过使用一个标志来设计一种退出策略,并定期检查线程。但是,我无法想到一种改变该标志值的方法/条件。有什么建议吗?
我有一个程序,不断地轮询数据库中某个字段的值是否发生变化。它在后台运行,目前使用while(true)和sleep()方法设置时间间隔。我想知道这是否是一种好的做法?还有,是否有更有效的实现方式?该程序需要始终运行。
因此,停止程序的唯一方法是对进程ID执行kill命令。该程序可能正在进行JDBC调用。如何更优雅地终止程序?我知道最好的选择是通过使用一个标志来设计一种退出策略,并定期检查线程。但是,我无法想到一种改变该标志值的方法/条件。有什么建议吗?
我想知道这是否是一个好的做法?
不是。有时候,这可能是你所拥有的唯一选择,但并不是好的做法。
那么,有什么更有效的方法来实现这个功能呢?
首先,数据是如何进入数据库的?
最好的改变是修复插入/更新数据库的程序,使请求同时到达数据库和您的程序。使用 JMS 主题处理这种情况非常好。
其次,可以在数据库中添加触发器,将每个插入/更新事件加入队列。该队列可以为您的程序提供处理的 JMS 主题(或队列)。
如果以上方法都无法实现,那么就只能使用轮询了。
但是,您的轮询循环不应该仅仅进行简单的工作。它应该将消息放入队列中,以供其他 JDBC 进程处理。终止请求是另一条可以放入 JMS 队列的消息。当您的程序接收到终止消息时,必须确保已经完成了之前的 JDBC 请求,并且可以优雅地停止。
在执行任何操作之前,请查看 ESB 解决方案。像 Sun 的 JCAPS 或 TIBCO 这样的公司已经拥有这项功能。开源 ESB,如 Mulesource 或 Jitterbit 可能已经内置并测试了此功能。
正如其他人所说,你需要轮询可能表明你的系统设计存在更深层次的问题...但有时候就是这样,所以...
如果你想更优雅地处理"终止"进程,你可以安装一个关机挂钩,在按下Ctrl+C时调用:
volatile boolean stop = false;
Runtime.getRuntime().addShutdownHook(new Thread("shutdown thread") {
public void run() {
stop = true;
}
});
然后定期检查停止变量。
更优雅的解决方案是等待事件:
boolean stop = false;
final Object event = new Object();
Runtime.getRuntime().addShutdownHook(new Thread("shutdown thread") {
public void run() {
synchronized(event) {
stop = true;
event.notifyAll();
}
}
});
// ... and in your polling loop ...
synchronized(event) {
while(!stop) {
// ... do JDBC access ...
try {
// Wait 30 seconds, but break out as soon as the event is fired.
event.wait(30000);
}
catch(InterruptedException e) {
// Log a message and exit. Never ignore interrupted exception.
break;
}
}
}
或者类似于此。
为SIGTERM设置一个信号处理程序,该程序设置一个标志,告诉您的循环在下一次执行时退出。
你可以将该字段设置为一个复合值,包括(概念上)进程ID和时间戳。[最好使用两个或更多字段]在拥有访问该字段的进程中启动一个线程,并使其循环,睡眠并更新时间戳。然后等待拥有访问该字段的轮询进程可以观察到时间戳在某个时间T内没有更新(远大于更新循环的睡眠间隔),并假定先前拥有该进程已经死亡。
但这仍然容易出现故障。
在其他语言中,我总是尝试使用flock()调用来同步文件。不确定Java的等效物是什么。如果可能的话,请尽可能获得真正的并发性。