Java while 循环和线程!
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/390242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java while loop and Threads!
提问by Epitaph
I have a program that continually polls the database for change in value of some field. It runs in the background and currently uses a while(true) and a sleep() method to set the interval. I am wondering if this is a good practice? And, what could be a more efficient way to implement this? The program is meant to run at all times.
我有一个程序可以不断轮询数据库以了解某些字段的值变化。它在后台运行,目前使用 while(true) 和 sleep() 方法来设置间隔。我想知道这是否是一个好习惯?而且,什么是更有效的实现方式?该程序旨在始终运行。
Consequently, the only way to stop the program is by issuing a kill on the process ID. The program could be in the middle of a JDBC call. How could I go about terminating it more gracefully? I understand that the best option would be to devise some kind of exit strategy by using a flag that will be periodically checked by the thread. But, I am unable to think of a way/condition of changing the value of this flag. Any ideas?
因此,停止程序的唯一方法是对进程 ID 发出终止命令。该程序可能处于 JDBC 调用的中间。我怎样才能更优雅地终止它?我知道最好的选择是通过使用由线程定期检查的标志来设计某种退出策略。但是,我想不出改变这个标志值的方法/条件。有任何想法吗?
采纳答案by S.Lott
I am wondering if this is a good practice?
我想知道这是否是一个好习惯?
No. It's not good. Sometimes, it's all you've got, but it's not good.
不,这不好。有时,这就是你所拥有的,但并不好。
And, what could be a more efficient way to implement this?
而且,什么是更有效的实现方式?
How do things get into the database in the first place?
事情首先是如何进入数据库的?
The best change is to fix programs that insert/update the database to make requests which go to the database and to your program. A JMS topic is good for this kind of thing.
最好的更改是修复插入/更新数据库的程序,以向数据库和您的程序发出请求。JMS 主题非常适合这种事情。
The next best change is to add a trigger to the database to enqueue each insert/update event into a queue. The queue could feed a JMS topic (or queue) for processing by your program.
下一个最好的更改是向数据库添加触发器以将每个插入/更新事件排入队列。队列可以提供一个 JMS 主题(或队列)供您的程序处理。
The fall-back plan is your polling loop.
后备计划是您的轮询循环。
Your polling loop, however, should not trivially do work. It should drop a message into a queue for some other JDBC process to work on. A termination request is another message that can be dropped into the JMS queue. When your program gets the termination message, it absolutely must be finished with the prior JDBC request and can stop gracefully.
但是,您的轮询循环不应该毫无意义地工作。它应该将一条消息放入队列中,以供其他 JDBC 进程处理。终止请求是另一个可以放入 JMS 队列的消息。当您的程序收到终止消息时,它绝对必须完成先前的 JDBC 请求并且可以正常停止。
Before doing any of this, look at ESB solutions. Sun's JCAPSor TIBCOalready have this. An open source ESB like Mulesourceor Jitterbitmay already have this functionality already built and tested.
在做任何这些之前,先看看 ESB 解决方案。Sun 的JCAPS或TIBCO已经有了这个。像Mulesource或Jitterbit这样的开源 ESB可能已经构建并测试了此功能。
回答by cletus
This is really too big an issue to answer completely in this format. Do yourself a favour and go buy Java Concurrency in Practice. There is no better resource for concurrency on the Java 5+ platform out there. There are whole chaptersdevoted to this subject.
这真的是一个太大的问题,无法以这种格式完全回答。帮自己一个忙,去购买Java Concurrency in Practice。在 Java 5+ 平台上没有更好的并发资源。有整章专门讨论这个主题。
On the subject of killing your process during a JDBC call, that should be fine. I believe there are issues with interrupting a JDBC call (in that you can't?) but that's a different issue.
关于在 JDBC 调用期间终止进程的问题,应该没问题。我相信中断 JDBC 调用存在问题(因为您不能?)但这是一个不同的问题。
回答by chaos
Set up a signal handler for SIGTERM that sets a flag telling your loop to exit its next time through.
为 SIGTERM 设置一个信号处理程序,该处理程序设置一个标志,告诉您的循环下次退出。
回答by OscarRyz
If that's your application and you can modify it, you can:
如果这是您的应用程序并且您可以修改它,您可以:
- Make it read a file
- Read for the value of a flag.
- When you want to kill it, you just modify the file and the application will exit gracefully.
- 让它读取文件
- 读取标志的值。
- 当你想杀死它时,你只需修改文件,应用程序就会优雅地退出。
Not need to work it that harder that that.
不需要那么努力。
回答by Dustin
Note that a Timer (or similar) would be better in that you could at least reuse it and let it do with all of the details of sleeping, scheduling, exception handling, etc...
请注意,计时器(或类似的)会更好,因为您至少可以重用它并让它处理睡眠,调度,异常处理等的所有细节......
There are many reasons your app could die. Don't focus on just the one.
您的应用程序可能会死掉的原因有很多。不要只关注一个。
If it's even theoretically possible for your JDBC work to leave things in a half-correct state, then you have a bug you should fix. All of your DB work should be in a transaction. It should go or not go.
如果您的 JDBC 工作在理论上甚至可能使事情处于半正确状态,那么您就有一个应该修复的错误。你所有的数据库工作都应该在一个事务中。应该去还是不去。
回答by noahlz
Regarding the question "The program could be in the middle of a JDBC call. How could I go about terminating it more gracefully?" - see How can I abort a running jdbc transaction?
关于“程序可能处于 JDBC 调用中间。我怎样才能更优雅地终止它?”这个问题。- 请参阅如何中止正在运行的 jdbc 事务?
Note that using a poll with sleep() is rarely the correct solution - implemented improperly, it can end up hogging CPU resources (the JVM thread-scheduler ends up spending inordinate amount of time sleeping and waking up the thread).
请注意,使用带有 sleep() 的轮询很少是正确的解决方案 - 实施不当,它最终可能会占用 CPU 资源(JVM 线程调度程序最终会花费过多的时间来休眠和唤醒线程)。
回答by jmucchiello
This is Java. Move your processing to a second thread. Now you can
这是爪哇。将您的处理移至第二个线程。现在你可以
- Read from stdin in a loop. If someone types "QUIT", set the while flag to false and exit.
- Create a AWT or Swing frame with a STOP button.
- Pretend you are a Unix daemon and create a server socket. Wait for someone to open the socket and send "QUIT". (This has the added bonus that you can change the sleep to a select with timeout.)
- 在循环中从 stdin 读取。如果有人键入“QUIT”,请将 while 标志设置为 false 并退出。
- 使用 STOP 按钮创建 AWT 或 Swing 框架。
- 假装你是一个 Unix 守护进程并创建一个服务器套接字。等待有人打开套接字并发送“QUIT”。(这有一个额外的好处,您可以将睡眠更改为带有超时的选择。)
There must be hundreds of variants on this.
必须有数百种变体。
回答by Bombe
I‘ve created a Service class in my current company's utility library for these kinds of problems:
我在我当前公司的实用程序库中为这些类型的问题创建了一个服务类:
public class Service implements Runnable {
private boolean shouldStop = false;
public synchronized stop() {
shouldStop = true;
notify();
}
private synchronized shouldStop() {
return shouldStop;
}
public void run() {
setUp();
while (!shouldStop()) {
doStuff();
sleep(60 * 1000);
}
}
private synchronized sleep(long delay) {
try {
wait(delay);
} catch (InterruptedException ie1) {
/* ignore. */
}
}
}
Of course this is far from complete but you should get the gist. This will enable you to simply call the stop()
method when you want the program to stop and it will exit cleanly.
当然,这还远未完成,但您应该了解要点。这将使您能够stop()
在希望程序停止时简单地调用该方法,并且它会干净地退出。
回答by Dave Ray
As others have said, the fact that you have to poll is probably indicative of a deeper problem with the design of your system... but sometimes that's the way it goes, so...
正如其他人所说,您必须进行轮询这一事实可能表明您的系统设计存在更深层次的问题……但有时就是这样,所以……
If you'd like to handle "killing" the process a little more gracefully, you could install a shutdown hook which is called when you hit Ctrl+C:
如果你想更优雅地处理“终止”进程,你可以安装一个关闭钩子,当你点击Ctrl+时调用它C:
volatile boolean stop = false;
Runtime.getRuntime().addShutdownHook(new Thread("shutdown thread") {
public void run() {
stop = true;
}
});
then periodically check the stop variable.
然后定期检查停止变量。
A more elegant solution is to wait on an event:
一个更优雅的解决方案是等待一个事件:
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;
}
}
}
Or something like that.
或类似的东西。
回答by skiphoppy
You could make the field a compound value that includes (conceptually) a process-ID and a timestamp. [Better yet, use two or more fields.] Start a thread in the process that owns access to the field, and have it loop, sleeping and updating the timestamp. Then a polling process that is waiting to own access to the field can observe that the timestamp has not updated in some time T (which is much greater than the time of the updating loop's sleep interval) and assume that the previously-owning process has died.
您可以将该字段设为包含(概念上)进程 ID 和时间戳的复合值。[更好的是,使用两个或更多字段。] 在拥有该字段访问权限的进程中启动一个线程,并让它循环、休眠和更新时间戳。然后等待拥有对该字段的访问权的轮询进程可以观察到时间戳在某个时间 T(远大于更新循环的睡眠间隔时间)内没有更新,并假设先前拥有的进程已经死亡.
But this is still prone to failure.
但这仍然容易失败。
In other languages, I always try to use flock() calls to synchronize on a file. Not sure what the Java equivalent is. Get real concurrency if you at all possibly can.
在其他语言中,我总是尝试使用 flock() 调用来同步文件。不确定 Java 等价物是什么。如果可能的话,获得真正的并发性。