class MyStore {

    int st[];
    int numItems;

    public MyStore(int len) {
	st = new int[len];
        numItems = 0;
    }

    public synchronized int getItem() {

	System.out.println(">---> enter getItem()");

	if ( numItems > 0 ) {
	    try {
		Thread.sleep(0);//(int)(Math.random() * 10000));
	    }
	    catch  (InterruptedException e) {
		System.out.println(e);
	    }
	}
	else {
	    try { System.out.println("wait in getItem() ...");
	    // Legt den diese Methode aufrufenden Thread
            // schlafen, bis aus einer anderen Methode
            // von einem anderen Thread ein notify()-Befehl
            // ausgeloest wird.
            // Mit dem wait()-Befehl wird der Monitor
            // fuer Methodenaufrufe durch andere Threads
            // freigegeben.
                  System.out.println("Start waiting in getItem() ...");
                  wait();
                  System.out.println("... stop waiting in getItem()");
            } catch (java.lang.InterruptedException e) { };
	}

	System.out.println("<---< return from getItem()");
        notify();
	return st[--numItems];

    }
 
    public synchronized  void putItem(int item) {

        System.out.println(">***> enter putItem(" + item + ")");

	if ( numItems < st.length ) {
	    try {
                // Wartezeit, um Verabreitung in putItem() zu 
                // simulieren
		Thread.sleep((int)(Math.random() * 10000));
	    }
	    catch  (InterruptedException e) {
		System.out.println(e);
	    }
	}
        else { 
          try { 
            System.out.println(">***> enter putItem(" + item 
			       + ") is waiting ...");
            wait(); 
            System.out.println(">***> enter putItem(" + item 
			       + ") ... wakes up");
          } catch (java.lang.InterruptedException e) { }; 
        }

        st[numItems++] = item;
        notify();

	System.out.println("<***< return from putItem(" + item + ")");

    }

    public int getNumItems() {
	return numItems;
    }

}

class GlobalObjects {

    public static MyStore g_store;
    public static final int maxItems = 10;

}

class Producer extends Thread {

    public String toString() { return "Producer"; }

    public void run() {

 
	while (true) {
	    try {
		int theItem = (int)(Math.random() * 10000);

		System.out.println(this + ": enter item with value " 
				   + theItem + " ... ");
		GlobalObjects.g_store.putItem(theItem);
		System.out.println(this + " ... done");
		
		Thread.sleep((int)(Math.random() * 2000));
	    }
	    catch  (InterruptedException e) {
		return;
	    }
	}

    }  

}

class Consumer extends Thread {

    public String toString() { return "Consumer"; }

    public void run() {

	while (true) {
            System.out.println("Consumer: get item with value ... ");
            System.out.println("Consumer: ... " 
		                + GlobalObjects.g_store.getItem());
	}


    }

}

public class Prod_con {

    public static void main(String[] args) {

        GlobalObjects.g_store = new MyStore(GlobalObjects.maxItems);

        System.out.println("start main");
        
        Producer prod = new Producer();
        Consumer con = new Consumer();
        
        new Thread(prod).start();
        new Thread(con).start();
    
    }

}
