Java while循环和线程!

时间:2008-12-23 22:26:50

标签: java multithreading while-loop

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

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

13 个答案:

答案 0 :(得分:12)

  

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

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

  

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

首先如何进入数据库?

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

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

回退计划是你的投票循环。

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

在执行任何此操作之前,请查看ESB解决方案。 Sun的JCAPSTIBCO已经拥有此功能。像MulesourceJitterbit这样的开源ESB可能已经构建并测试了此功能。

答案 1 :(得分:8)

在这种格式下完全回答这个问题确实太大了。帮自己一个忙,去买Java Concurrency in Practice。在Java 5+平台上没有更好的并发资源。 整章致力于此主题。

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

答案 2 :(得分:6)

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

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

或类似的东西。

答案 3 :(得分:3)

请注意,一个Timer(或类似的)会更好,因为你至少可以重复使用它,并让它处理睡眠,调度,异常处理等所有细节......

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

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

答案 4 :(得分:3)

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

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

此处必须有数百种变种。

答案 5 :(得分:2)

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

答案 6 :(得分:1)

关于“程序可能正在进行JDBC调用的问题。我怎样才能更优雅地终止它?” - 见How can I abort a running jdbc transaction?

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

答案 7 :(得分:0)

如果那是你的申请,你可以修改它,你可以:

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

不需要更努力地工作。

答案 8 :(得分:0)

我在当前公司的实用程序库中为这些问题创建了一个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()方法,它就会完全退出。

答案 9 :(得分:0)

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

但这仍然容易失败。

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

答案 10 :(得分:0)

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

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

答案 11 :(得分:0)

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

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

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

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

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

您也可以使用thread.sleep(miliseconds);来降低轮询线索的压力(因为它不会经常轮询)。

答案 12 :(得分:0)

Java9有另一个潜力"回答这个问题:Thread.onSpinWait()

  

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

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