Just to reinforce things. The reason to call wait() is because you are waiting for a particular state to be achieved - which will be signified by someone calling notify or notifyAll. That state has to be, by definition, shared mutable state (it is shared between you and the notifier thread and it must be mutable or you will be waiting a very very very long time). As you know access to shared mutable state must always be performed while holding a suitable lock (AtomicXXX and lock-free concurrent collections not-withstanding). So you have to hold the lock to check the state you are going to wait() upon. The wait() atomically releases the lock and suspends the thread. The notification thread then acquires the lock, modifies the state and calls notify()/notifyAll(). At that point the wait()ing thread is removed from the wait-set and is now waiting to reacquire the lock that the notifying thread may not have yet released. When the waiting thread returns from wait() it owns the lock again and should then re-check the state to see if the new state is what it is waiting for. If it is then, generally, while still holding the lock the thread performs some action that relied on the object being in the state it waited for.
Note that wait() must always be called in a loop testing the condition being waited upon. Spurious wakeups are permitted and do occur.
To me, I think the reason of requiring the synchonization is to ensure the atomicity of "checking the status and wait" operations. So that no other thread can change the status in the middle.