我被Java的notify()搞糊涂了。下面的例子来自一本教科书。
public synchronized consume() {
while(queue.isEmpty()) {
try{ wait(); } catch (InterruptedException e) {}
}
// Assume that getElement() notifies to producers.
element = queue.getElement();
...
}
public synchronized produce() {
while(queue.isFull()) {
try{ wait(); } catch (InterruptedException e) {}
}
element = new Element();
...
queue.addElement(element);
notifyAll();
}我非常理解上面例子中的produce()方法。但是,谁能告诉我为什么我们不在第一个方法(consume())的末尾使用notifyAll()?简而言之,为什么不这样做:
public synchronized consume() {
while(queue.isEmpty()) {
try{ wait(); } catch (InterruptedException e) {}
}
// Assume that getElement() notifies to producers.
element = queue.getElement();
...
notifyAll();
}非常感谢!
诚挚的问候。
发布于 2012-04-12 08:37:44
我同意你的观点,@Slash。在您的代码示例中,由于您要从队列中删除和元素,因此需要有人通知在isEmpty()循环中等待的生产者。然而,您的代码会说:
// Assume that getElement() notifies to producers.
element = queue.getElement();所以这个注释意味着getElement()以某种方式调用了notify()或notifyAll()。
简而言之,
为什么不像这样:
是的,你的代码可以工作,尽管你需要删除注释。:-)
通常,在这些生产者/消费者模式中,有两个锁:一个在队列为空时,另一个在队列已满时。然后,当队列不再满时,消费者可以向生产者发出信号,而不会唤醒其他消费者。在这种情况下,您也可以使用单个notify(),因为您只需要唤醒单个消费者或单个生产者。这里使用notifyAll()是因为只有一个对象是synchronized on的。
另外,对于后人来说,请注意while()循环不是if语句,这一点非常重要。即使您使用的是notify()和两个锁,在多生产者/消费者模型中也存在竞争条件,必须加以保护。此外,虚假唤醒也是一个问题。更多信息请看这里:
http://256stuff.com/gray/docs/misc/producer_consumer_race_conditions/
发布于 2012-04-12 08:37:36
在这种情况下,在生产时使用通知,告诉消费者现在有东西可以消费,这样他们中的一个就可以唤醒并消费它。
假设在getElement()中发生了通知,当消费者刚刚消费了一些东西时:
// Assume that getElement() notifies to producers.https://stackoverflow.com/questions/10115889
复制相似问题