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

嗨,我一直在努力解决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();
    }
}
主类:

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