Search code examples
javamultithreadingsynchronizationproducer-consumer

Producer consumer not giving desired result


I'm learning thread synchronization from java documentation. I implemented a famous problem Producer-consumer problem. But it is not giving result as expected. I've searched a lot about this problem at HERE, HERE, HERE, HERE, HERE and some other stack-exchange and non-stack exchange sites but unable to resolve my problem. Here is my code:

GetSetItem.java

public class GetSetItem {

   private volatile boolean available = false;

   private int item;

   public synchronized void set(int item) {
      while(available) {
        try {
            wait();
         } catch (InterruptedException ie) {
            System.err.println("Interrupted: " + ie.getMessage());
         }
       }

       this.item = item;
       available = true;
       notifyAll();
   }

   public synchronized int get() {
      while(!available) {
        try {
           wait();
         } catch (InterruptedException ie) {
            System.err.println("Interrupted: " + ie.getMessage());
         }
       }
       available = false;
       notifyAll();
       return item;
   }

}

Consumer.java

public class Consumer implements Runnable {

   private int number; // Just for show #1,#2 etc. For future use
   private GetSetItem consumer;

   public Consumer(GetSetItem item, int seq) {
      consumer = item;
      number = seq;
   }

   @Override
   public void run() {
      int value = -1;

      for(int i = 0; i < 10; i++) {
         value = consumer.get();
         System.out.println("Consumer #" + number + " get: " + value);
      }

   }
}

Producer.java

public class Producer implements Runnable  {

    private GetSetItem producer;

    private int number = 0;

    public Producer(GetSetItem item, int seq) {
       producer = item;
       number = seq;
    }

    @Override
    public void run() {
       for(int i = 0; i < 10; i++) {
         producer.set(i);
         System.out.println("Producer #" + number + " Put: " + i);
       }
    }

}

ProducerConsumerMain.java

public class ProducerConsumerMain {

    public static void main(String[] args) {

       GetSetItem item = new GetSetItem();

       Producer p = new Producer(item, 1);
       Consumer c = new Consumer(item, 1);

       new Thread(p).start();
       new Thread(c).start();

    }

}

Output is:

Consumer #1 get: 0
Producer #1 Put: 0
Producer #1 Put: 1
Consumer #1 get: 1
Producer #1 Put: 2
Consumer #1 get: 2
Producer #1 Put: 3
Consumer #1 get: 3
Producer #1 Put: 4
Producer #1 Put: 5
Consumer #1 get: 4
Consumer #1 get: 5
Producer #1 Put: 6
Producer #1 Put: 7
Consumer #1 get: 6
Consumer #1 get: 7
Consumer #1 get: 8
Producer #1 Put: 8
Producer #1 Put: 9
Consumer #1 get: 9

But Output should be in producer -> consumer format. It mean consumer can consume an item only if it is available and produced by producer. I've also tried private boolean available = false instead of private volatile boolean available = false; but not receiving expected output.

So please tell me what wrong I'm doing and how can I successfully implement this problem.


Solution

  • I solved the problem by using the System.out.println(...) statement in get() and set() methods of GetSetItem class and removing System.out.println(...) from corresponding producer and consumer class. As:
    get() Method of GetSetItem.java

    public synchronized void set(int item, int number) {
        while(available) {
            try {
            wait();
            } catch (InterruptedException ie) {
            System.err.println("Interrupted: " + ie.getMessage());
            }
        }
    
        this.item = item;
    
    
        /* Putting this line here gives expected output because this   
         * statement is synchronized due to method synchronization.  
         */
            System.out.println("Producer #" + number + " Produced: " + item);            
    
            available = true;
            notifyAll();
    }
    

    set() method of GetSetItem.java

    public synchronized int get(int number) {
        while (!available) {
            try {
            wait();
            } catch (InterruptedException ie) {
            System.err.println("Interrupted: " + ie.getMessage());
            }
        }
        /*
         * Putting this line here gives expected output because this statement
         * is synchronized due to method synchronization.
         */
    
    
        System.out.println("Consumer #" + number + " Consumed: " + item);
    
    
        available = false;
        notifyAll();
        return item;
    }
    

    EDIT: output:

    Producer #1 Produced: 0
    Consumer #1 Consumed: 0
    Producer #1 Produced: 1
    Consumer #1 Consumed: 1
    Producer #1 Produced: 2
    Consumer #1 Consumed: 2
    Producer #1 Produced: 3
    Consumer #1 Consumed: 3
    Producer #1 Produced: 4
    Consumer #1 Consumed: 4
    Producer #1 Produced: 5
    Consumer #1 Consumed: 5
    Producer #1 Produced: 6
    Consumer #1 Consumed: 6
    Producer #1 Produced: 7
    Consumer #1 Consumed: 7
    Producer #1 Produced: 8
    Consumer #1 Consumed: 8
    Producer #1 Produced: 9
    Consumer #1 Consumed: 9