title: Multiple monitor synchronization using java thread
body: <p>I am writing a tiny application (something a bit bigger than "HelloWorld"). The task is to create a single producer and several consumers. The producer generates integeres and puts them in a dynamic stack (which is my monitor object), and consumers try to get those integers from stack. 
  I do know how to create 1 producer + 1 consumer using a flag and a while with wait() inside. But how to do the same with multiple consumers. </p>
  
  <p>Please have a look at my code: </p>
  
  <pre><code>public interface StackQueueIF {
      void push(int value);
      int pop();
  }
  
  public class DynamicStack implements StackQueueIF{
  
      private volatile int stck[];
      private volatile int tos;
  
      boolean valueSet = false;
  
      public DynamicStack(int size) {
          stck = new int[size];
          tos = -1;
      }
  
      @Override
      public synchronized void push(int item) {
          while(valueSet){
              try {
                  wait();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
  
          if (tos == stck.length-1) {
              System.out.println("---------STACK HAS BEEN DOUBLED--------");
              int temp[] = new int[stck.length * 2];
              for (int i = 0; i &lt; stck.length; i++)   temp[i] = stck[i];
              stck = temp;
              stck[++tos] = item;
          }else
              stck[++tos] = item;
  
          valueSet = true;
          notifyAll();
      }
  
      @Override
      public synchronized int pop() {
          while(!valueSet){
              try {
                  wait();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
  
          valueSet = false;
          notifyAll();
          return stck[tos--];
      }
  }
  
  class Producer implements Runnable{
      StackQueueIF queue;
      String producerName;
      private static int counter = 0;
  
      public Producer(StackQueueIF queue, String name) {
          this.queue = queue;
          this.producerName = name;
          new Thread(this,producerName).start();
      }
  
      @Override
      public void run() {
          while(true){
              System.out.println(this.producerName + " puts " + (++counter) 
                + " into stack");
              this.queue.push(counter);
              try {
                  Thread.sleep(500);
              } catch (InterruptedException e) {
                  System.err.println(producerName + " interrupted");
                  e.printStackTrace();
              }
          }
      }
  }
  
  class Consumer implements Runnable{
      StackQueueIF queue;
      String consumerName;
  
      public Consumer(StackQueueIF queue, String consumerName) {
          this.queue = queue;
          this.consumerName = consumerName;
          new Thread(this, this.consumerName).start();
      }
  
      @Override
      public void run() {
          while(true){
              System.out.println(this.consumerName + " gets " + queue.pop() + " from stack");
              try {
                  Thread.sleep(500);
              } catch (InterruptedException e) {
                  System.err.println(consumerName + "interrupted");
                  e.printStackTrace();
              }
          }
      }
  
  }
  
  public class QueueTester {
      public static void main(String[] args) {
          StackQueueIF queue = new DynamicStack(10);
          new Producer(queue,"Producer №1");
  
          new Consumer(queue,"Consumer №1");
          new Consumer(queue,"Consumer №2");
      }
  }
  </code></pre>