Java中的多个生产者和消费者问题(没有BlockingQueue)

时间:2011-03-02 14:48:31

标签: java concurrency pthreads

我正在刷新我对Java并发的记忆,我正在玩流行的生产者消费者问题。我已经实现了以下代码,如果有一个生产者和一个消费者,它可以正常工作。但是,如果有多个生产者/消费者,它将无法正常运行。我不明白为什么

public class ProducerConsumer {

    static Monitor monitor;

    public ProducerConsumer(int maxSize)
    {
        monitor = new Monitor(maxSize);
        new Producer().start();
        new Producer().start();
        new Consumer().start();
        new Consumer().start();
    }

    class Producer extends Thread{

        @Override
        public void run() {
            while(true)
            {
                try {
                    monitor.insert();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Consumer extends Thread{

        @Override
        public void run() {
            while(true)
            {
                try {
                    monitor.remove();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

     class Monitor {

          int n;
          int maxSize;

         public Monitor(int maxSize)
         {
             n=0;
             this.maxSize = maxSize;
         }

        synchronized void insert() throws InterruptedException 
        {
            if(n==maxSize)
                wait();
            System.out.println("Producer: "+n++);
            if(n==1)
                notifyAll();
        }

        synchronized void remove() throws InterruptedException 
        {
            if(n==0)
                wait();
            System.out.println("Consumer: "+n--);
            if(n==maxSize-1)
                notifyAll();
        }
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer(100);

    }
}

1 个答案:

答案 0 :(得分:8)

wait()应始终按以下方式使用:

while(condition not met) 
    wait();

否则某些线程可以唤醒并在条件仍未满足时继续。这种情况有两种可能的原因:

  1. 当你调用notifyAll()时,你唤醒所有等待的线程,因此当条件再次为假时(即当有限的资源已经被其他线程耗尽时),其中一些可能为时已太晚。
  2. 有可能出现虚假的唤醒(即线程在没有相应的notify的情况下醒来。)
  3. 如果您实际上只需唤醒一个主题,则可以使用notify()代替notifyAll()。它消除了第一个问题,但仍无法保护您免受虚假唤醒,因此仍然需要while