Saturday, September 24, 2016

How to solve Producer Consumer problem in Java using wait and notify method

Producer Consumer problem can be easily solved by using just wait and notify method using inter-thread communication where one thread is used to produce and another thread is used to consume. Here the wait and notify method will be used for inter-thread communication to notify other party (Producer by Consumer thread and vice-versa).

To solve this problem, I have used the ArrayList as shared object, where producer thread puts the object (Just Integer in this case) and consumer thread consumes the object (integer). Interestingly, I have used the same list object as monitor lock, thus removing the additional overhead to create shared monitor lock.


Here is the code example:


import java.util.ArrayList;

public class ProducerConsumer {

 public static void main (String[] args) {
  ArrayList<Integer> list = new ArrayList<Integer>();
  Thread t1 = new Thread(new Producer(list));
  Thread t2 = new Thread(new Consumer(list));
  t1.start();
  t2.start();
  
 }
}

class Producer implements Runnable {
 
 private ArrayList<Integer> list;
 Producer(ArrayList<Integer> list) {
  this.list = list;
 }

 @Override
 public void run() {
  int count = 1;
  while(count <= 3) {
   synchronized(list) {
    list.add(count);
    System.out.println("Produced ::"+ count);
    count++;
    try {
     list.notify();
     list.wait();
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
  
 }
}


class Consumer implements Runnable {
 
 private ArrayList<Integer> list;
 Consumer(ArrayList<Integer> list) {
  this.list = list;
 }
 
 @Override
 public void run() {
  int count = 1;
  while(count <= 3) {
   synchronized(list) {
    while(list.size() == 0){
     try {
      list.notify();
      list.wait();
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
    Integer value = list.remove(0);
    System.out.println("Consumed ::"+ value);
    count++;
    try {
     list.notify();
     list.wait();
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
 }
}

Output:

Produced ::1
Consumed ::1
Produced ::2
Consumed ::2
Produced ::3
Consumed ::3

Explanations:

In the above code example, we are starting two threads (one Producer and one Consumer). To avoid the consumer start executing and consuming first, I have put code to check if producer has already produced or not (i.e. if there is anything on list or not). This is to address race-condition between producer and consumer threads.
Here, the producer thread is putting 3 objects (Integer in the example) in the list. Please note that the call by Producer thread and Consumer thread to put objects and retrieve objects is synchronized on the same lock (array list object in this example). This way, we guarantee that either the code of producer or code of consumer is executing inside cpu and not both at the same time. We have produced three objects and consumed three synchronously i.e producer put one, consumer consumed then again producer produced another  and ...
So, when producer produced an object, it calls notify to make sure that if the consumer threads is in waiting state, it goes back to runnable state and ready to consume and the producer thread goes to wait state (and releasing the lock) and then consumer thread which has been in runnable states gets the lock (after producer releases it), consumes the object, notify the producer to produce another and same cycle repeats for the 3 times.

That's all for the solution of producer consumer problem using wait and notify method with the help of above code example. If you have any question. please feel free to ask in comment section.