在Java中使用轮询是不是很糟糕?

时间:2012-08-28 12:48:03

标签: java multithreading

我有几个ArrayLists作为数据队列。每个队列都链接到一个单独的线程,用于检查ArrayList中是否包含某些数据。

 while (array.size == 0) {
    // nothing
 }

 // do stuff with one element of the array
 // remove element from array
 // and call the loop again

我在嵌入式系统编程中做过类似的事情,但在Java中使用它是否安全?关注的是通过在非常快的时间内循环迭代来处理过程功耗。

可以通过添加Thread.sleep(100)来解决,并且每100毫秒检查一次,然后再次检查 - 响应时间变慢。

问题是 - 我是否需要添加睡眠,或者我不应该关注它?

有关更安全/更好的系统检查数组中新数据的任何建议吗?

7 个答案:

答案 0 :(得分:53)

ArrayList不是线程安全集合,因此如果一个线程将数据添加到列表中,而另一个线程尝试从同一列表中检索数据,则无法保证其他线程将看到添加的元素。

忙着等你描述的东西不必要地消耗cpu资源。

由于您似乎需要一个队列,为什么不使用一个队列,例如ArrayBlockingQueue。它有一个take method,它会在不消耗CPU周期的情况下阻塞,直到项目被添加到队列中。它是线程安全的。

答案 1 :(得分:11)

除非您需要等待的时间非常短,因此上下文切换太昂贵,我不会使用旋转。它绝对没有充分的理由浪费CPU周期。

您应该使用wait/notify或其他一些信号机制暂停线程并仅在必要时将其唤醒。

对于更高级的构造,生成器 - 消费者模式有专门的数据结构,如BlockingQueue(选择实现):

  

另外支持等待队列的操作的队列   在检索元素时变为非空,并等待空间   存储元素时在队列中可用。

答案 2 :(得分:2)

如何使用在java 5中发布的阻塞队列之类的东西。我认为现在建议使用wait / notify,这会变得相当复杂。我用过它并且效果很好。

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html

答案 3 :(得分:1)

java.lang.ArrayList根本不是线程安全的。出于排队目的,最好使用BlockingQueue。如果队列为空而不消耗cpu,它会阻止线程调用。您可以根据需要使用ArrayBlockingQueueLinkedBlockingQueue或其他队列实施。

即使您可以使用wait and notifyAll实施它,但始终建议您使用BlockingQueue

答案 4 :(得分:1)

您可以使用Concurrent集合,例如ArrayBlockingQueue

,而不是使用ArrayList。
ArrayBlockingQueue<YourObject> theQueue;
while(true) {
  YourObject o = theQueue.take();
 //process your object
}

在另一个你填充队列的地方,你只需要做一个

theQueue.add(theElement);

等待对象的线程将“休眠”直到有元素。 add方法将唤醒消费线程。

您可以在此处详细了解此课程:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ArrayBlockingQueue.html

答案 5 :(得分:0)

没有睡眠,您的线程将尽可能快地循环并访问ArrayList,可能大多数时候没有任何结果。

我建议实现一个Listener / Observer模式。如果可以的话,让填充ArrayList的生产者通知相应的线程进行更改。因此,您将从轮询行为转变为推送行为。

不确定您的架构中是否可行,但需要对您的系统进行进一步说明。

答案 6 :(得分:0)

什么是投票?问题是什么?

反复测试一个条件直到它变为真的过程被称为轮询。

轮询通常在循环的帮助下实现,以检查特定条件是否为真。如果确实如此,则采取某些行动。这浪费了许多CPU周期并使实现效率低下。 例如,在一个经典的排队问题中,一个线程正在生成数据而另一个正在使用它。

Java多线程如何解决这个问题?

为避免轮询,Java使用三种方法,即wait()notify()notifyAll()

所有这些方法都属于Object类,因此所有类都有它们。它们必须仅在同步块中使用。

wait() - 它告诉调用线程放弃锁定并进入休眠状态,直到某个其他线程进入同一个监视器并调用notify()

notify() - 唤醒在同一对象上调用wait()的单个线程。应该注意的是,调用notify()实际上并没有放弃对资源的锁定。

notifyAll() - 唤醒在同一对象上调用wait()的所有线程。

ArrayList不是线程安全的集合。使用ArrayBlockingQueue

Class ArrayBlockingQueue