java线程同步中没有信号量的生产者-消费者问题
嗨,我一直在努力解决java中没有信号量的生产者-消费者问题。当我使用单一生产者和单一消费者时,我的代码运行良好。但是,当我添加多个消费者时,它就完全搞砸了,所有消费者线程都进入了同步块。我不知道为什么会这样。这是我的密码: 制作人类别:java线程同步中没有信号量的生产者-消费者问题,java,multithreading,producer-consumer,Java,Multithreading,Producer Consumer,嗨,我一直在努力解决java中没有信号量的生产者-消费者问题。当我使用单一生产者和单一消费者时,我的代码运行良好。但是,当我添加多个消费者时,它就完全搞砸了,所有消费者线程都进入了同步块。我不知道为什么会这样。这是我的密码: 制作人类别: public class Producer implements Runnable { Object SharedObject = null; String producerName= null; Random rn = new Ra
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();
}
}
主类:
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();
}
}
您正在producer中使用
notifyAll
,这会唤醒所有等待监视器的使用者线程。如果您只想唤醒一名消费者,则应使用以下菜单中的notify
:
唤醒正在该对象监视器上等待的单个线程
notifyAll()
唤醒在此对象监视器上等待的所有线程
notifyAll()
对于您的消费者来说,当他们醒来时,最好实际检查他们是否可以使用资源。如果要继续使用notifyAll
,消费者应该能够被唤醒,如果可用资源不足,请返回等待
我建议打印
main.itemCount
。这将使你的问题更加明显
您在呼叫时必须注意
notify
为什么您的制作人
只在只有一个项目可用时才呼叫通知
?当有可用的商品时,生产商是否应该呼叫通知
消费者
只告诉制作人
在有4个项目时醒来(这不是满了吗?) 实际上,将notifyAll()改为notify()的方法很有效!!!谢谢大家的建议。这是我的密码:
制片人级别:
package com.source;
导入java.util.Random
公共类生产者实现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();
}
}
}
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;
导入java.util.Random
公共类使用者实现可运行{
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();
}
}
}
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;
公共班机{
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();
}
}
再次感谢大家宝贵的时间和建议。听起来你已经克服了最初的问题,但这里还有一些反馈
我相信您真正的问题不是因为notifyAll()
而是因为您的缓冲区测试是if
测试,而不是while
循环。有一些典型的竞争条件,线程被唤醒,但缓冲区中没有元素。看见因此,您的代码应该类似于:
while (Main.itemCount == Main.bufferSize) {
及
调用notifyAll()
会加剧问题,但即使只调用notify()
,竞争条件仍然存在。随着你增加更多的消费者或其他生产商,你会看到更多的问题
这里是一些其他的反馈
- 要非常小心锁内的锁。这是一个典型的坏模式,我很少使用。您真的需要同步
consume()
- 对象实例名称应以小写字母开头,因此应为
sharedObject
- 如果可能,您锁定的任何对象都应该是
private final
。您不会希望它更改为另一个对象
- 使用
Main.
任何模式都是错误的。使用itemCount
和bufferSize
创建一个对象,然后将该对象的相同实例传递给所有生产者和消费者,怎么样?它也是您要锁定的对象
- 注意不要像其他人建议的那样,在线程代码中散布
System.out.println(…)
消息System.out
是一个同步类,因此这将添加锁和内存同步,从而可能移动或修复问题。对调试线程程序很困难
你不知道类和对象-你是如何达到这个水平的??!我不确定是什么给你留下了这样的印象,但我真的很想知道代码中的错误。谢谢。您好,谢谢您的回复,我将producer中的监视器更改为notify(),即使这样也无法获得预期的结果。当我使用notifyAll()时,我假设即使所有的使用者都被它唤醒,因为我们有同步块,我假设在给定的时间只有一个线程在块内。现在我将其更改为notify(),但无法继续…@CaptainCold更新了答案。您的实现存在更多问题。我正在回答为什么所有消费者线程都会唤醒。根据我的代码,消费者只有在商品计数为“0”时才会进入等待阶段,因此我只是添加了一个条件,以便在商品计数为“1”时通知消费者,因为当计数为“0”以外的任何值时,消费者都不会等待。对于生产者来说,类似的事情是,生产者只有在缓冲区满了(即5)时才会进入睡眠阶段,因此我们只需要在消费者消费物品时唤醒生产者,使物品计数为4,一旦物品计数为4,生产者就会唤醒,并继续尝试控制锁来添加物品。同时,即使消费者…再次消费,计数也将减少到3、2和1,但在所有这些情况下,生产商已经收到通知,并试图获取锁。@mattm