您好我一直在努力解决没有信号量的java中的生产者消费者问题。当我使用单个生产者和单个消费者时,我的代码工作正常。但是,当我添加多个消费者时,它完全搞乱,所有消费者线程都进入同步块。我不确定为什么会这样。这是我的代码:
制作人类:
public class Producer implements Runnable {
Object SharedObject = null;
String producerName= null;
Random rn = new Random();
public Producer(Main m, String s) {
this.SharedObject = m;
this.producerName=s;
}
public Producer(Main m) {
this.SharedObject = m;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == Main.bufferSize) {
try {
System.out.println("Producer is sleeping and waiting for notification form Consumer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount++;
System.out.println(this.producerName+" Produced the item and the item count is : " + Main.itemCount);
if (Main.itemCount == 1) {
SharedObject.notify();
System.out.println("Producer Notified the cosumer to wake up");
}
}
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
消费者类:
public class Consumer implements Runnable {
Object SharedObject = null;
String consumerName= null;
Random rn = new Random();
public Consumer(Main m, String s) {
SharedObject = m;
this.consumerName=s;
}
Consumer c= new Consumer((Main) SharedObject,consumerName);
synchronized void consume(){
synchronized (SharedObject) {
if (Main.itemCount == 0) {
try {
System.out.println(this.consumerName+" is sleeping and waiting for notify from Producer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount--;
System.out.println(this.consumerName+" consumed 1 item and the item Count is " + Main.itemCount);
if (Main.itemCount == 4) {
SharedObject.notifyAll();
System.out.println("Consumer notified the producer to wake up");
}
}
}
public void run() {
while (true) {
c.consume();
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
主要类别:
public class Main {
static int itemCount = 0;
static int bufferSize = 5;
public static void main(String[] args) {
Main m = new Main();
Thread objP = new Thread(new Producer(m, "Producer1"));
Thread objC = new Thread(new Consumer(m, "Consumer1"));
Thread objC2 = new Thread(new Consumer(m, "Consumer2"));
Thread objC3 = new Thread(new Consumer(m, "Consumer3"));
objP.start();
objC.start();
objC2.start();
objC3.start();
}
}
答案 0 :(得分:0)
您在生产者中使用notifyAll
,它会唤醒在监视器上等待的所有消费者线程。如果您只想让一位消费者醒来,您应该使用notify
来自API documentation:
notify()
唤醒正在此对象监视器上等待的单个线程。
notifyAll()
唤醒等待此对象监视器的所有线程。
对于您的消费者而言,当他们被唤醒时,实际检查他们是否可以消耗资源也会更好。如果您想继续使用notifyAll
,则应该能够唤醒消费者,如果资源不足,请返回等待。
我建议打印main.itemCount
。这将使您所遇到的问题变得更加明显。
当你打电话notify
时,你必须注意。
为什么只有一个项目可用时,producer
才会调用notify
?只要有可用的项目,制作人不应该致电notify
吗?
consumer
只会告诉producer
当有4个项目时(这不是已满)?
答案 1 :(得分:0)
实际上将notifyAll()更改为notify()kindoff work !!!谢谢你们的建议。这是我的代码:
制作人类:
package com.source;
import java.util.Random;
public class Producer实现Runnable {
Object SharedObject = null;
String producerName = null;
Random rn = new Random();
public Producer(Main m, String s) {
this.SharedObject = m;
this.producerName = s;
}
public Producer(Main m) {
this.SharedObject = m;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == Main.bufferSize) {
try {
System.out
.println(this.producerName + "is sleeping and waiting for notification form Consumer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount++;
System.out.println(this.producerName + " Produced the item and the item count is : " + Main.itemCount);
if (Main.itemCount == 1) {
SharedObject.notify();
System.out.println("Producer Notified the cosumer to wake up");
}
}
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
消费者类:
package com.source;
import java.util.Random;
public class Consumer实现Runnable {
Object SharedObject = null;
String consumerName = null;
Random rn = new Random();
public Consumer(Main m, String s) {
SharedObject = m;
this.consumerName = s;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == 0) {
try {
System.out.println(this.consumerName + " is sleeping and waiting for notify from Producer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount--;
System.out.println(this.consumerName + " consumed 1 item and the item Count is " + Main.itemCount);
if (Main.itemCount == 4) {
SharedObject.notify();
System.out.println("Consumer notified the producer to wake up");
}
}
try {
int i = rn.nextInt(1000);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
主类:
package com.source;
public class Main {
static int itemCount = 0;
static int bufferSize = 5;
public static void main(String[] args) {
Main m = new Main();
Thread objP = new Thread(new Producer(m, "Producer1"));
Thread objC = new Thread(new Consumer(m, "Consumer1"));
Thread objC2 = new Thread(new Consumer(m, "Consumer2"));
Thread objC3 = new Thread(new Consumer(m, "Consumer3"));
Thread objP2 = new Thread(new Producer(m, "Producer2"));
Thread objP3 = new Thread(new Producer(m, "Producer3"));
objP.start();
objC.start();
objC2.start();
objC3.start();
objP2.start();
objP3.start();
}
}
再次感谢大家的宝贵时间和建议。
答案 2 :(得分:0)
听起来你已经过了最初的问题,但这里有更多的反馈意见。
我认为你真正的问题不是因为notifyAll()
,而是因为你的缓冲区测试是if
测试而不是while
循环。有一些经典的竞争条件,一个线程被唤醒,但缓冲区中有 no 元素。见my notes here。所以你的代码应该是这样的:
while (Main.itemCount == Main.bufferSize) {
和
while (Main.itemCount == 0) {
调用notifyAll()
会加剧问题,但即使只有notify()
,竞争条件仍然存在。随着您添加更多消费者或其他生产者,您将看到更多问题。
以下是其他一些反馈。
非常小心锁中的锁。这通常是一种糟糕的模式,而且我很少使用它。你真的需要同步consume()
吗?
对象实例名称应以小写字母开头,因此应为sharedObject
。
如果可能,您锁定的任何对象都应为private final
。你不希望它改成另一个对象。
使用Main.
任何东西都是不好的模式。如何使用itemCount
和bufferSize
创建一个对象,然后将该对象的相同实例传递给我们的所有生产者和消费者?它也是你要锁定的对象。
小心使用其他人推荐的System.out.println(...)
消息来填充您的线程代码。 System.out
是一个同步类,因此这将添加可以移动或修复问题的锁和内存同步。是。调试线程程序是 hard 。