Producer - Consumer Problem in Java

UPDATED: 31 May 2015

What is Producer - Consumer Problem?
In Simple term we can say, when two Process trying to access same(commonly shared) resource at the same time and one failed to do its operation because another process is using that resource.

In this article we'll generate the Producer - Consumer problem using threads that are trying to access common resource. One thread that is adding/removing records to the List<Integer> and another thread trying to print the records of List<Integer> one-by-one.


Source Code(Problem Generation)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ProducerConsumerExample {

   /* Create common List of Integer. */
   private static List<Integer> listIntegers = new ArrayList<Integer>();
 
   public static void main(String[] args) {
      /* Start Producer Thread */
      new ProducerThread().start();
      /* Start Consumer Thread */
      new ConsumerThread().start();
   }
 
   /* Producer thread that will add/remove records to `listIntegers` */
   public static class ProducerThread extends Thread{
  
      @Override
      public void run() {
         int index = 0; 
         while(true){
            try {
               /* Put thread in sleep for `1 milliseconds` */
               Thread.sleep(1);
            } catch (Exception e) {
               e.printStackTrace();
            }
    
            if(listIntegers.size() < 100){
               /* Add record to List */
               listIntegers.add(index);
               /* Print the records of List */
               System.out.println("Producer Thread: \n" + listIntegers);
               index++;
            }else{
               /* Remove 1st element from List */
               listIntegers.remove(0);
            }
         }
      }
   }

   /* Consumer thread that will iterate records of `listIntegers` */
   public static class ConsumerThread extends Thread{
  
      @Override
      public void run() {
         while(true){
            try {
               /* Put thread in sleep for `1 milliseconds` */
               Thread.sleep(1);
            } catch (Exception e) {
               e.printStackTrace();
            }
            System.out.println("Consumer Thread iterator list: ");
            /* Get iterator of List */
            Iterator<Integer> iterator = listIntegers.iterator();
            /* Iterate List until last element */
            while(iterator.hasNext()){
               /* Print the element */
               System.out.print(iterator.next() + ", ");
               if(!iterator.hasNext()){
                  System.out.println("");
               }
            }
         }
      }
   }
}
When you run the above program it'll throw an exception java.util.ConcurrentModificationException as shown in following output.

Note: When you execute this program in your system you won't get same output. It depends upon the execution of Thread in your system.

Output 
As you can see clearly portion marked within =. Consumer Thread Iterating the List<Integer> and printed 0 and at the same time Producer Thread added record and Consumer Thread thrown an exception.
/* Removed few lines from output. It printed data of list from 0 to 3 */
Producer Thread: 
[0, 1, 2, 3, 4]
Consumer Thread iterator list: 
0, 1, 2, 3, 4, 
Producer Thread: 
[0, 1, 2, 3, 4, 5]
==========================================
Consumer Thread iterator list: 
0, Producer Thread: 
[0, 1, 2, 3, 4, 5, 6]
Exception in thread "Thread-1" Producer Thread: 
[0, 1, 2, 3, 4, 5, 6, 7]
java.util.ConcurrentModificationException
 at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
 at java.util.ArrayList$Itr.next(Unknown Source)
 at javaQuery.thread.ProducerConsumerExample$ConsumerThread.run(ProducerConsumerExample.java:51)
==========================================


Solution


We can solve this problem using synchronized keyword. synchronized takes care for accessing List<Integer>, while one thread is accessing the List<Integer> another thread has to wait until first thread finishes its work.

Source Code(Solving Problem)
Following program will not give java.util.ConcurrentModificationException exception.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ProducerConsumerExample {

   /* Create common List of Integer. */
   private static List<Integer> listIntegers = new ArrayList<Integer>();
 
   public static void main(String[] args) {
      /* Start Producer Thread */
      new ProducerThread().start();
      /* Start Consumer Thread */
      new ConsumerThread().start();
   }
 
   /* Producer thread that will add/remove records to `listIntegers` */
   public static class ProducerThread extends Thread{
  
      @Override
      public void run() {
         int index = 0;  
         while(true){
            try {
               /* Put thread in sleep for `1 milliseconds` */
               Thread.sleep(1);
            } catch (Exception e) {
               e.printStackTrace();
            }
    
            /* synchronized block */
            synchronized (listIntegers) {
               if(listIntegers.size() < 100){
                  /* Add record to List */
                  listIntegers.add(index);
                  /* Print the records of List */
                  System.out.println("Producer Thread: \n" + listIntegers);
                  index++;
               }else{
                  /* Remove 1st element from List */
                  listIntegers.remove(0);
               }
            }
         }
      }
   }

   /* Consumer thread that will iterate records of `listIntegers` */
   public static class ConsumerThread extends Thread{
  
      @Override
      public void run() {
         while(true){
            try {
               /* Put thread in sleep for `1 milliseconds` */
               Thread.sleep(1);
            } catch (Exception e) {
               e.printStackTrace();
            }
            System.out.println("Consumer Thread iterator list: ");
    
            /* synchronized block */
            synchronized (listIntegers) {
               /* Get iterator of List */
               Iterator<Integer> iterator = listIntegers.iterator();
               /* Iterate List until last element */
               while(iterator.hasNext()){
                  /* Print the element */
                  System.out.print(iterator.next() + ", ");
                  if(!iterator.hasNext()){
                     System.out.println("");
                  }
               }
            }
         }
      }
   }
}


0 comments :