Java while循环和线程!

我有一个程序,不断轮询数据库以获取某些字段值的变化。 它在后台运行,目前使用while(true)和sleep()方法来设置间隔。 我想知道这是一个好习惯吗? 而且,实现这一点可能是一种更有效的方法? 该计划旨在始终运行。

因此,停止程序的唯一方法是对进程ID发出kill。 该程序可能处于JDBC调用的中间。 我怎么能更优雅地终止它呢? 我知道最好的选择是通过使用将由线程定期检查的标志来设计某种退出策略。 但是,我无法想到改变这个标志值的方式/条件。 有任何想法吗?

我想知道这是一个好习惯吗?

不,这不好。 有时,这就是你所拥有的一切,但它并不好。

而且,实现这一点可能是一种更有效的方法?

事情如何首先进入数据库?

最好的更改是修复插入/更新数据库的程序,以发出进入数据库和程序的请求。 JMS主题适用于此类事情。

下一个最佳更改是向数据库添加触发器,以将每个插入/更新事件排入队列。 队列可以提供JMS主题(或队列)以供程序处理。

后备计划是您的轮询循环。

但是,您的轮询循环不应该轻松地完成工作。 它应该将消息放入队列以供其他JDBC进程处理。 终止请求是可以放入JMS队列的另一条消息。 当您的程序获得终止消息时,绝对必须使用先前的JDBC请求完成并且可以正常停止。

在执行任何此操作之前,请查看ESB解决方案。 Sun的JCAPS或TIBCO已经有了这个。 像Mulesource或Jitterbit这样的开源ESB可能已经构建并测试了这个function。

在这种格式下完全回答这个问题确实太大了。 帮自己一个忙,然后去实践中购买Java Concurrency 。 在Java 5+平台上没有更好的并发资源。 整篇章节专门讨论这个问题。

关于在JDBC调用期间终止进程的问题,这应该没问题。 我相信中断JDBC调用有问题(你不能这样做?)但这是一个不同的问题。

正如其他人所说,你必须进行民意调查的事实可能表明你的系统设计存在更深层次的问题……但有时这就是它的方式,所以…

如果你想更好地处理“杀死”这个过程,你可以安装一个关闭钩子,当你按下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; } } } 

或类似的东西。

请注意,Timer(或类似)会更好,因为您至少可以重复使用它,并让它完成睡眠,调度,exception处理等所有细节……

您的应用可能会死的原因有很多。 不要只关注那一个。

如果理论上你的JDBC工作甚至可以将事物保持在半正确的状态,那么你就应该修复一个bug。 您的所有数据库工作都应该在事务中。 应该去还是不去。

这是Java。 将处理移至第二个线程。 现在你可以

  • 从循环中的stdin读取。 如果有人键入“QUIT”,请将while标志设置为false并退出。
  • 使用STOP按钮创建AWT或Swing框架。
  • 假装您是一个Unix守护进程并创建一个服务器套接字。 等待有人打开sockets并发送“退出”。 (这有额外的好处,您可以将睡眠更改为超时选择。)

必须有数百个变种。

为SIGTERM设置一个信号处理程序,设置一个标志告诉你的循环下一次退出。

关于“程序可能正在进行JDBC调用的问题。我怎样才能更优雅地终止它?” – 请参阅如何中止正在运行的jdbc事务?

请注意,使用带有sleep()的轮询很少是正确的解决方案 – 实现不当,最终会占用CPU资源(JVM线程调度程序最终会花费大量时间来hibernate和唤醒线程)。

我在当前公司的实用程序库中为这些问题创建了一个Service类:

 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. */ } } } 

当然,这远非完整,但你应该得到要点。 这样您就可以在希望程序停止时简单地调用stop()方法,它将干净地退出。

如果这是您的应用程序并且您可以修改它,您可以:

  • 让它读取文件
  • 读取标志的值。
  • 当你想杀死它时,你只需修改文件,应用程序就会正常退出。

不需要那样努力工作。

您可以将该字段设置为包含(概念上)进程ID和时间戳的复合值。 [更好的是,使用两个或更多字段。]在拥有对字段的访问权限的进程中启动一个线程,并使其循环,hibernate和更新时间戳。 然后,等待访问该字段的轮询进程可以观察到时间戳在某个时间T内没有更新(这比更新循环的hibernate间隔的时间长得多)并且假设先前拥有的进程已经死亡。

但这仍然容易失败。

在其他语言中,我总是尝试使用flock()调用来同步文件。 不确定Java等价物是什么。 如果你可能的话,获得真正的并发。

我很惊讶没人提到Java中实现的中断机制。 它应该是解决线程停止问题的解决方案。 所有其他解决方案至少有一个缺陷,这就是为什么需要在Java并发库中实现此机制的原因。

您可以通过向线程发送一个interrupt()消息来停止线程,但还有其他方法可以使线程中断。 发生这种情况时,会抛出InterruptedException。 这就是为什么你在调用sleep()时必须处理它的原因。 这就是你可以进行清理并优雅地结束的地方,比如关闭数据库连接。

Java9有另一个“潜在的”答案: Thread.onSpinWait() :

表示调用者暂时无法进展,直到其他活动发生一个或多个操作为止。 通过在自旋等待循环结构的每次迭代中调用此方法,调用线程向运行时指示它正在忙等待。 运行时可以采取措施来提高调用自旋等待循环结构的性能。

有关详细信息,请参阅JEP 285 。

我认为你应该用timertask轮询它。

我的电脑在10秒内运行了1075566次循环。 这是一秒钟107557次。

轮询真正需要多长时间? TimerTask以1秒的最快速度运行1000次。 你给它一个int(miliseconds)参数作为参数。 如果您对此感到满意 – 这意味着您可以使用该任务减少108倍的CPU压力。

如果您对每秒的轮询(108 * 1000)感到满意。 紧张减少108000倍。 这也意味着你可以检查108000个值与你的while循环相同的cpu应变 – 因为你不经常分配你的cpu进行检查。 记住cpu有一个时钟周期。 我的是3 600 000 000赫兹(每秒周期数)。

如果您的目标是为用户更新它 – 您可以在每次用户登录时运行检查(或手动让他请求更新) – 这实际上不会对cpu造成任何压力。

你也可以使用thread.sleep(miliseconds); 降低轮询线程的压力(因为它不经常轮询)你在哪里做。