import java.util.*;

//
//   The push(int n) function blocks any thread that accesses
//   it if the stack is full.  See the infinite while thread
//   blocking code. 
//   Similarly the pop employs the same technique.

// The sleep statements are designed to fill the stack up as
// roughly twice as many are put in as are poped.

// I have corrected the code to use a general technique
// where the thread is blocked at a condition and put
// in a wait state.  While the original code did the job
// it did not do it in a generic way.  See pop() where
// the commented out notify() was the authors original code
// and I have moved this to when the process is finished.
// So there are two good reasons for moving this here, firstly
// why notify other objects that may want to use your object
// when you do, secondly the technique is now general : aquire
// resource first, then use, then release.  All functions just
// have to implement the pattern.  The author wrote the code
// having two threads only in mind.

// The print statements inside the thrown exception code is not 
//   called, but there to verify this.

public class StackDemo extends Thread
{

  static final int MAXSTACK=6;
  static final int MAXNUM=100;

  public int stack[] = new int[MAXSTACK];
  private int next=0;
  private Random r=new Random();
  
  private synchronized void push(int n)
  {
    try
    {
      while (next==MAXSTACK)
        wait();
      stack[next]=n;
      ++next;
      notify();
    }
    catch (InterruptedException e)
    {
      System.out.println("exception in push");
    }
  }

  public synchronized int pop()
  {
    int res=-1;
    try
    {
      //notify();
      while (next==0)
        wait();

      res=stack[next-1];
      --next;
      notify();
    }
    catch (InterruptedException e)
    {
      System.out.println("exception in pop");
    }

    return res;
  }

  public void run()
  {
    try
    {
      while (true)
      {
        int k = Math.abs(r.nextInt()%MAXNUM);
        push(k);
        System.out.println("added " + k + " to stack");
        sleep(1000);  
      }
    }
    catch (InterruptedException ie) 
    {
      System.out.println("exception in run");
    }

  }

  public static void main(String args[])
  {
    StackDemo demo = new StackDemo();
    demo.start();
    new StackUser(demo).start();
  }

}






