Java while循环和线程!

Java while循环和线程!,java,multithreading,while-loop,Java,Multithreading,While Loop,我有一个程序,它不断地轮询数据库中某个字段值的变化。它在后台运行,当前使用while(true)和sleep()方法设置间隔。我想知道这是否是一个好的做法?那么,有什么更有效的方法来实现这一点呢?该程序应始终运行 因此,停止程序的唯一方法是在进程ID上发出一个杀戮。程序可以处于JDBC调用的中间。我怎样才能更优雅地结束它呢?我知道最好的选择是通过使用线程定期检查的标志来设计某种退出策略。但是,我想不出改变此标志值的方法/条件。有什么想法吗?这真是一个太大的问题,用这种方式无法完全回答。帮你自己一

我有一个程序,它不断地轮询数据库中某个字段值的变化。它在后台运行,当前使用while(true)和sleep()方法设置间隔。我想知道这是否是一个好的做法?那么,有什么更有效的方法来实现这一点呢?该程序应始终运行


因此,停止程序的唯一方法是在进程ID上发出一个杀戮。程序可以处于JDBC调用的中间。我怎样才能更优雅地结束它呢?我知道最好的选择是通过使用线程定期检查的标志来设计某种退出策略。但是,我想不出改变此标志值的方法/条件。有什么想法吗?

这真是一个太大的问题,用这种方式无法完全回答。帮你自己一个忙,去买吧。在Java5+平台上没有更好的并发资源。有整整一章专门讨论这个主题


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

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

我想知道这是否是一个好的做法

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

那么,有什么更有效的方法来实现这一点呢

首先,事情是如何进入数据库的

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

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

后备计划是您的轮询循环

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


在执行这些操作之前,先看看ESB解决方案。太阳的或者已经有了这个。类似或可能已经构建并测试了此功能的开源ESB。

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

  • 让它读一个文件
  • 读取标志的值
  • 当您想要杀死它时,只需修改文件,应用程序就会正常退出
不需要那么费力地工作。

请注意,计时器(或类似的)会更好,因为您至少可以重用它,让它处理睡眠、调度、异常处理等所有细节

你的应用程序可能会死掉的原因有很多。不要只关注其中一个

如果您的JDBC工作在理论上有可能保持半正确状态,那么您就有一个bug需要修复。您的所有数据库工作都应该在一个事务中。关于“程序可以在JDBC调用中间的问题”,

< p>。我如何才能更优雅地终止它?-参见


请注意,使用poll with sleep()很少是正确的解决方案-如果执行不当,它可能会占用CPU资源(JVM线程调度程序最终花费过多的时间睡眠和唤醒线程)。

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

  • 在循环中读取标准输入。如果有人键入“退出”,请将while标志设置为false并退出
  • 使用停止按钮创建AWT或回转机架
  • 假设您是一个Unix守护进程,并创建一个服务器套接字。等待某人打开套接字并发送“退出”。(这增加了一个额外的好处,即您可以将睡眠更改为带超时的选择。)

这上面肯定有数百种变体。

我在当前公司的实用程序库中创建了一个服务类,用于解决此类问题:

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()
方法,它将干净地退出。

正如其他人所说,您必须轮询的事实可能表明您的系统设计存在更深层次的问题。。。但有时候就是这样,所以

如果您想更优雅地处理“终止”进程,您可以安装一个关机挂钩,当您点击Ctrl+C时会调用它:

然后定期检查停止变量

更优雅的解决方案是等待事件:

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;
        }
    }
}

或者类似的东西。

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

但这仍然容易失败


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

我很惊讶没有人提到Java中实现的中断机制。它应该是停止线程问题的解决方案。所有其他解决方案都至少有一个缺陷,这就是为什么需要在
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;
        }
    }
}