"BufferExample" shows basic usage of "sychronized", "wait" and "notify". The example creates a 'consumer' thread which interacts with the main thread through a shared instance of "Buffer". The main thread places the numbers 1..7 into the buffer. The consumer extracts them and prints them. In the Buffer class, notice how all of the methods are defined to be synchronized. This means that, when those methods are invoked, the calling thread has to acquire a mutual exclusion lock associated with the buffer object. The lock does not prevent external access to the fields of the buffer: we need to make the fields "private" in order to achieve that. The invocations of "wait" cause the calling thread to atomically (i) release the lock that it holds on the buffer object and (ii) block waiting until it receives a notification. The invocations of "notifyAll" cause all of the threads waiting for notification on that object to be released. Notice how they must then compete to re-acquire the mutual exclusion lock associated with the object -- they can't proceed right away. The "Buffer" class illustrates the usual way in which these facilities are used: (i) mark all methods synchronized, (ii) make all fields private, (iii) at the start of each method loop calling wait() until some kind of entry condition is satisfied (e.g. the buffer is empty) and then (iv) at the end of each method call notifyAll() so that any waiting threads can re-evaluate their conditions.