title: My Produce Consumer Hangs
body: <p>Please copy the program below and try running in your IDE. It's a simple Produce Consumer implementation - it runs fine when I use one Producer and one Consumer thread but fails when using 2 each. Please let me know the reason why this program hangs or is there anything else wrong with it.</p>
  
  <pre><code>import java.util.LinkedList;
  import java.util.Queue;
  
  public class PCQueue {
  
   private volatile Queue&lt;Product&gt; productQueue = new LinkedList&lt;Product&gt;();
  
   public static void main(String[] args) {
    PCQueue pc = new PCQueue();
  
    Producer producer = new Producer(pc.productQueue);
    Consumer consumer = new Consumer(pc.productQueue);
  
    new Thread(producer, "Producer Thread 1").start();
    new Thread(consumer, "Consumer Thread 1").start();
  
    new Thread(producer, "Producer Thread 2").start();
    new Thread(consumer, "Consumer Thread 2").start();
   }
  
  }
  
  class Producer implements Runnable {
  
   private Queue&lt;Product&gt; queue = null;
  
   private static volatile int refSerialNumber = 0;
  
   public Producer(Queue&lt;Product&gt; queue) {
    this.queue = queue;
   }
  
   @Override
   public void run() {
  
    while (true) {
     synchronized (queue) {
      while (queue.peek() != null) {
       try {
        queue.wait();
       } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
       }
      }
      queue.add(new Product(++refSerialNumber));
      System.out.println("Produced by: "
        + Thread.currentThread().getName() + " Serial Number: "
        + refSerialNumber);
  
      queue.notify();
     }
    }
  
   }
  }
  
  class Consumer implements Runnable {
  
   private Queue&lt;Product&gt; queue = null;
  
   public Consumer(Queue&lt;Product&gt; queue) {
    this.queue = queue;
   }
  
   @Override
   public void run() {
    while (true) {
     synchronized (queue) {
      while (queue.peek() == null) {
       try {
        queue.wait();
       } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
       }
      }
  
      Product product = queue.remove();
      System.out.println("Consumed by: "
        + Thread.currentThread().getName() + " Serial Number: "
        + product.getSerialNumber());
  
      queue.notify();
  
     }
    }
  
   }
  
  }
  
  class Product {
   private int serialNumber;
  
   public Product(int serialNumber) {
    this.serialNumber = serialNumber;
   }
  
   public int getSerialNumber() {
    return serialNumber;
   }
  }
  </code></pre>