具有多个使用者的java Producer使用notify()失败
我有这段代码,它是一个模拟生产者-消费者问题的代码,在一个共享的Q类对象上使用一个生产者和多个消费者。我在这里使用notify()而不是notifyAll(),因为我需要理解为什么这段代码会进入死锁或无限等待状态
我的观点是:如果有一个生产者和多个消费者,那么notify()将只调用一个处于等待状态的线程,其余线程将保持在wait()状态。然后,生产者将再次恢复,因此代码将继续执行
观察:这里所有线程的生产者和消费者都处于无限等待状态。代码如下所示:
public class ProdConsProb {
public static void main(String[] args) {
Q q = new Q();
Thread producerThread = new Thread(new Producer(q), "producerThread");
Thread consumerThread = new Thread(new Consumer(q), "Consumer1");
Thread consumerAnotherThread = new Thread(new Consumer(q), "Consumer2");
Thread consumerYetAnotherThread = new Thread(new Consumer(q), "Consumer3");
producerThread.start();
consumerThread.start();
consumerAnotherThread.start();
consumerYetAnotherThread.start();
}
}
class Producer implements Runnable {
Q q;
public Producer(Q q) {
this.q = q;
}
@Override
public void run() {
int i = 0;
while (true)
try {
q.setN(i++);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
Q q;
public Consumer(Q q) {
this.q = q;
}
@Override
public void run() {
while (true)
try {
q.getN();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Q {
private int n = 0;
boolean valueSet = false;
public synchronized int getN() throws InterruptedException {
while (!valueSet)
{
wait();
}
valueSet = false;
notify();
return n;
}
public synchronized void setN(int n) throws InterruptedException {
while (valueSet == true)
{
wait();
}
this.n = n;
valueSet = true;
notify();
}
}
我添加了一些系统输出。生成的日志如下所示:
producerThread :: SetN : Valueset is false
producerThread :: Producer inserted 0
producerThread :: SetN : Valueset after is true
producerThread :: SetN : Valueset is true
producerThread wait() ------------ Active
producerThread :: SetN :Wait() Valueset is true
Consumer3 Start :: GetN : Valueset is true
Consumer3 :: Consumer read 0
Consumer3 End :: GetN : Valueset after is false
Consumer3 Start :: GetN : Valueset is false
Consumer3 wait() ------------ Active
Consumer3 :: GetN :Wait() Valueset is false
Consumer2 Start :: GetN : Valueset is false
Consumer2 wait() ------------ Active
Consumer2 :: GetN :Wait() Valueset is false
Consumer1 Start :: GetN : Valueset is false
Consumer1 wait() ------------ Active
Consumer1 :: GetN :Wait() Valueset is false
producerThread wait() ------------- left
producerThread :: Producer inserted 1
producerThread :: SetN : Valueset after is true
producerThread :: SetN : Valueset is true
producerThread wait() ------------ Active
-->> producerThread :: SetN :Wait() Valueset is true
Consumer3 wait() left
Consumer3 :: Consumer read 1
Consumer3 End :: GetN : Valueset after is false
Consumer3 Start :: GetN : Valueset is false
Consumer3 wait() ------------ Active
Consumer3 :: GetN :Wait() Valueset is false
???? Consumer2 wait() left
Consumer2 wait() ------------ Active
Consumer2 :: GetN :Wait() Valueset is false
奇怪的是,一旦生产者在插入1后通知消费者,消费者3就会读取数据并通知生产者。现在producer 3必须从其wait()返回触发器,但customer2线程离开其wait()并返回wait()
注意:这段代码与notifyAll()配合使用,但我正在寻找notify()失败的原因
# 1 楼答案
它失败是因为生产者和消费者在同一个监视器上等待,而内在锁不支持单独的条件。如果发生通知,生产者或消费者都可以收到。但给定的通知将仅适用于其中一个。当一个线程收到一个只有另一个可以执行的通知时,该通知没有任何作用:被通知的线程醒来,发现它正在等待的条件仍然为false,然后返回等待状态
如果你看看ArrayBlockingQueue,它是用ReentrantLock实现的,有单独的条件,一个用于消费者,一个用于生产者,这样这种错误就不会发生