title: Custom Producer Consumer
body: <p>I tried a Producer Consumer program.. Sometimes the output is correct, sometimes exception occurs in middle of output although the program runs to completion.. </p>
  
  <p>I get <code>IndexOutOfBoundsException</code> and I believe the reason being the following:- when the Q is empty, all the 3 consumer threads go into waiting state; when the producer adds an item and notifies all the waiting threads, after a consumer thread removes the item,the other consumer thread waking up will try to remove(when the Q is now empty) which causes this problem.. I know its a race condition but not able to figure out how to avoid it... Any ideas/suggestions are welcome.</p>
  
  <p>Another query - Am not able to figure out a way to gracefully terminate this program.. As of now I have used <code>System.exit(0)</code> when the last item is produced.. Any other better ideas are welcome.</p>
  
  <h2>P.S</h2>
  
  <p>I don't want to use any java's API synchronized classes, I wanted try using <code>wait()/notify()</code> mechanism..</p>
  
  <pre><code>class Producer implements Runnable
  {
      private Queue q;
      Producer(Queue q)
      {
          this.q = q;
      }
      @Override
      public void run() { 
          for(int i =0;i&lt;50;i++)
              try {
                  q.add(new Integer(i));
              } catch (InterruptedException e) {  
                  e.printStackTrace();
              }   
      }
  }
  class Consumer extends Thread
  {
      private Queue q;
      Consumer(Queue q)
      {
          this.q = q;
      }   
      public void run()
      {       
          try {
              while(true)
              {
              System.out.println(Thread.currentThread().getName()+"-"+ q.get());
              }
          } catch (InterruptedException e) {      
              e.printStackTrace();
          }
      }
  }
  public class Main 
  {
      public static void main(String args[])
      {
      Queue q = new Queue();
      Producer runObj = new Producer(q);
      Thread producerObj = new Thread(runObj,"Producer");
      producerObj.start();    
      Consumer c1 = new Consumer(q);
      Consumer c2 = new Consumer(q);
      Consumer c3 = new Consumer(q);
      c1.setName("c1");
      c2.setName("c2");
      c3.setName("c3");
      c1.start();
      c2.start();
      c3.start(); 
      }
  }
  </code></pre>
  
  <p>Queue Class:</p>
  
  <pre><code>public class Queue {
  
      private ArrayList&lt;Integer&gt; itemQ;
      int qSize = 5;
  
      Queue()
      {
          itemQ = new ArrayList&lt;Integer&gt;();
      }
  
      public synchronized void add(Integer item) throws InterruptedException
      {
  
          if(itemQ.size() == qSize)
          {
              System.out.println("Q is full");
              wait();
          }
          System.out.println(item);
          if(item.equals(new Integer(49)))
          {
              System.out.println("Out Of Stock");
              System.exit(0);
  
          }
          itemQ.add(item);
          notifyAll();
      }
  
      public synchronized Integer get() throws InterruptedException
      {
          if(itemQ.isEmpty())
          {
              wait();
          }   
          Integer item = itemQ.remove(0);     
          notify();       
          return item;
      }
  }
  </code></pre>