The following is a demo of using wait and notify in Java and what it does is explained in the code comments.

This method of using wait and notify for inter-thread signalling has now been superseded since Java 5 with its addition of the concurrency package.
The classes in that package make implementing Java thread synchronization easier, with much richer functionality. It's instructive to compare the two ways of doing things, and you can see the concurrency package version HERE. The source file for the below is HERE

/**
 * Show how wait and notify work together
 *
 * We create a Thread 'sleepy' that keeps
 * falling asleep and will be awoken at
 * random intervals by several 'waker' threads
 *
 * @author Charles Johnson
 */
public class WakeUp {
    final Object lock = new Object();

    private void start() {
        Thread sleepy = new Thread() {
                public void run() {
                    while (true) {
                        try {
                            synchronized (lock) {
                                lock.wait();
                            }
                        } catch (InterruptedException e) {
                            /* ignore */
                        }

                        System.out.println("'sleepy' says: I'm awake!");
                    } // end while
                }
            };

        sleepy.start();
        startWakers();
    }

    private void startWakers() {
        final int NUM_WAKERS = 5;

        for (int i = 0; i < NUM_WAKERS; i++) {
            Waker w = new Waker();
            w.start();
        }
    }

    public static void main(String[] args) {
        new WakeUp().start();
    }

    /**
     * This Thread will wake up 'sleepy' after
     * random interval 'howLong', announcing its intentions
     * in the console first
     *
     */
    private class Waker extends Thread {
        private long howLong;
        private String name;

        public Waker() {
            // Give it a random interval
            howLong = (int) (Math.random() * 5000);
            // Give it a name using its interval
            name = String.format("%d-ms-waker", howLong);
        }

        /**
         * Sleep for random interval 'howLong' and then wake 'sleepy'
         */
        public void run() {
            try {
                Thread.sleep(howLong);
                // Waker up 'sleepy'
                System.out.printf("Thread %s about to wake up the sleeper...\n",
                    name);

                synchronized (lock) {
                    lock.notify();
                }
            } catch (InterruptedException e) {
                // ignore
            }
        }
    }
}