public class NotifyExample {

    class Waiter extends Thread {

	private Notifyer n;
	private int      nr;

	public Waiter(Notifyer n, int nr) {
	    this.n = n;
	    this.nr = nr;
	}
	public void run() {
	    n.waitForNotification();
	    System.out.println("Thread " + nr + " executed!");
	}
    }

    class Notifyer {

	boolean notificated = false;
	boolean doNotifyAll = false;

	public Notifyer(boolean doNotifyAll) {
	    this.doNotifyAll = doNotifyAll;
	}

	synchronized public void waitForNotification() {
	    while(!notificated) {
		try {
		    wait();
		} catch(InterruptedException e) {}
		System.out.println("happened?");
	    }
	}
	synchronized public void sendNotification() {
	    notificated = true;
	    if(doNotifyAll) {
		notifyAll();
	    } else {
		notify();
	    }
	}
    }

    private NotifyExample(boolean doNotifyAll) {
	Notifyer n = new Notifyer(doNotifyAll);
	for(int i=0; i<4; ++i) {
	    (new Waiter(n, i)).start();
	}
	n.sendNotification();
    }

    private static void printHelp() {
	System.out.println("\nNotifyExample");
	System.out.println("*************");
	System.out.println("\nThis program shows the difference between");
	System.out.println("the use of notify() and notifyAll()...");
	System.out.println("Try both native and green Threads! ;)");
	System.out.println("\n\njava [-native] NotifyExample notifyAll | notify\n\n");
	System.exit(0);
    }

    public static void main(String[] args) {
	if(args.length == 0) {
	    printHelp();
	} else if(args[0].compareTo("notify") == 0) {
	    new NotifyExample(false);
	} else if(args[0].compareTo("notifyAll") == 0) {
	    new NotifyExample(true);
	} else {
	    printHelp();
	}
    }
}
