我对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()
。但是,任何人都可以告诉我为什么我们不在第一种方法(notifyAll()
)的末尾使用consume()
?简而言之,为什么不喜欢这样:
public synchronized consume() {
while(queue.isEmpty()) {
try{ wait(); } catch (InterruptedException e) {}
}
// Assume that getElement() notifies to producers.
element = queue.getElement();
...
notifyAll();
}
非常感谢!
最好的问候。
答案 0 :(得分:6)
我同意你@Slash。在您的代码示例中,由于您要从队列中删除元素,因此有人需要通知正在isEmpty()
循环中等待的生产者。但您的代码却说:
// Assume that getElement() notifies to producers.
element = queue.getElement();
因此,评论意味着以某种方式getElement()
调用notify()
或notifyAll()
。
简而言之,为什么不喜欢这样:
是的,虽然您需要删除评论,但您的代码仍然有效。 : - )
通常在这些生产者/消费者模式中,有两个锁:一个是队列为空时,一个是满的。然后,当队列不再满,并且不唤醒其他消费者时,消费者可以向生产者发出信号。在这种情况下,您也可以使用单个notify()
,因为您只需要唤醒单个消费者或单个生产者。此处使用notifyAll()
,因为只有一个对象synchronized
。
此外,对于子孙后代,您注意到while()
循环是不是 if
语句,非常重要。即使您使用notify()
和两个锁,也必须保护多生产者/消费者模型中的竞争条件。虚假的唤醒也是一个问题。更多相关内容:
http://256stuff.com/gray/docs/misc/producer_consumer_race_conditions/
答案 1 :(得分:1)
在这种情况下,通知在生成时使用,告诉消费者现在有东西要消耗,以便其中一个可以唤醒并消费它。
通知消费者刚刚消费了什么东西,假设发生在getElement():
中// Assume that getElement() notifies to producers.