生产者在java线程同步中没有信号量的消费者问题

时间:2017-02-02 19:29:34

标签: java multithreading producer-consumer

您好我一直在努力解决没有信号量的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();
    }
}

3 个答案:

答案 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.任何东西都是不好的模式。如何使用itemCountbufferSize创建一个对象,然后将该对象的相同实例传递给我们的所有生产者和消费者?它也是你要锁定的对象。

  • 小心使用其他人推荐的System.out.println(...)消息来填充您的线程代码。 System.out是一个同步类,因此这将添加可以移动或修复问题的锁和内存同步。是。调试线程程序是 hard