wait / notify in Java
Condition waiting inside synchronized, spurious wakeups, while-loop guard.
Sleep until something changes
obj.wait() releases obj's monitor and suspends the thread until another thread calls notify() or notifyAll() on the same object. Releasing matters: it lets other threads enter and change the state. Before wait() returns, the thread re-acquires the lock.
synchronized (queue) {
while (queue.isEmpty()) {
queue.wait();
}
return queue.remove();
}You must hold the lock
wait(), notify() and notifyAll() may only be called by a thread that owns that object's monitor, i.e. inside synchronized (obj). Otherwise they throw IllegalMonitorStateException. It doesn't matter whether anyone is waiting.
Your turn
No synchronized block in sight. What happens?
Object lock = new Object();
lock.wait();Throws IllegalMonitorStateExceptionWaits foreverCompile error
Show the answer
It throws IllegalMonitorStateException straight away. main doesn't own lock's monitor, so it isn't allowed to wait on it. The same goes for notify().
while, never if
synchronized (queue) {
if (queue.isEmpty()) {
queue.wait();
}
return queue.remove();
}After waking, the queue may be empty again: another consumer got there first, or the wakeup was spurious. remove() then crashes.
synchronized (queue) {
while (queue.isEmpty()) {
queue.wait();
}
return queue.remove();
}Re-checks the condition after every wakeup, so it only proceeds when there really is an item.
notify() vs notifyAll()
notify() wakes one arbitrary waiter, which may be waiting for a *different* condition. If it can't proceed, the signal is lost and others may wait forever. notifyAll() wakes everyone; each re-checks its own condition in its while loop. Prefer notifyAll() unless one waiter is surely enough.
Why not sleep?
Thread A waits for done inside synchronized (this). Why use wait() there instead of Thread.sleep(10) in the loop?
Think about it, then reveal the answer
sleep() keeps holding the lock, so thread B, which must enter synchronized (this) to set done = true, can never get in. wait() releases the monitor, letting B in, and wakes up when notified instead of polling.
In practice
Modern code rarely calls wait/notify directly: BlockingQueue, CountDownLatch and Condition do it for you, with fewer traps. But the producer-consumer with wait/notify is an interview favorite, and "why while, not if?" is the follow-up question every interviewer asks.
Key takeaways
- Call wait/notify only while holding that object's lock
- wait() releases the lock; it re-acquires it before returning
- Guard with while (!condition) wait(); — never if
- Prefer notifyAll() unless one waiter is surely enough
Spurious wakeups are officially allowed: Object.wait()'s own javadoc warns a thread can wake without notify, and recommends the while-loop idiom.
Practice questions
What does this print?
Object lock = new Object();
lock.notify();
System.out.println("notified");- Throws IllegalMonitorStateException
- notified
- Compile error
- Throws InterruptedException
Check your answer
Throws IllegalMonitorStateException. notify() requires the calling thread to own the object's monitor. Without synchronized (lock), it throws IllegalMonitorStateException.
Why is notifyAll() usually safer than notify()?
- notify() wakes one arbitrary waiter, which may be waiting for a different condition
- notifyAll() releases the lock immediately
- notify() only works on the main thread
- notifyAll() removes the need for a while loop
Check your answer
notify() wakes one arbitrary waiter, which may be waiting for a different condition. If the single woken thread can't proceed, the signal is lost and others may wait forever. notifyAll() wakes everyone, and each re-checks its own condition.