3ashmawy
3ashmawy

Reputation: 469

Multiple Producers and consumers problem in Java (Without BlockingQueue)

I am refreshing my memory about Java concurrency and I was playing around with the popular producer consumer problem. I have implemented the below code which works correctly if there is a single producer and a single consumer. However, It doesn't function correctly if there are multiple producers/consumers. I can't see why

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);

    }
}

Upvotes: 2

Views: 7196

Answers (1)

axtavt
axtavt

Reputation: 242726

wait() should always be used in the following way:

while(condition not met) 
    wait();

Otherwise some thread can wake up and continue when condition is still not met. There are two possible reasons for this situation:

  1. When you call notifyAll(), you awake all waiting threads, so that some of them can be too late, when condition is false again (i.e. when limited resource is already exhausted by other threads).
  2. There is a possibility of spurious wakeups (i.e. thread wakes up without corresponding notify).

If you actually need to wake up only one thread, you can use notify() instead of notifyAll(). It eliminates the first problem, but still can't protect you from spurious wakeups, so that while is still required.

Upvotes: 8

Related Questions