Explanation
What just happened
napper went to sleep inside synchronized. A sleeping thread stops running, but it keeps every lock it holds. other needed the same lock, so it sat BLOCKED for napper’s entire nap.
Try the what-if switch
wait() releases it: lock.wait() gives up the lock and parks the thread until another thread calls notify() or notifyAll(). notifier got in at once. When waiter woke up, it had to take the lock back first, so it was briefly BLOCKED until notifier left.
The difference
Thread.sleep(ms) |
lock.wait() |
|
|---|---|---|
| Holds the lock? | yes | no, gives it up |
| Wakes up when | time runs out | notified (or timeout) |
| Where | anywhere | only inside synchronized (lock) |
| Belongs to | Thread (static) |
Object |
When to use which
Use sleep() to pause, never while holding a lock. Use wait() to wait for a condition another thread will make true, always in a loop:
while (!ready) lock.wait();
In modern code
wait/notify is low level and easy to get wrong. A BlockingQueue, CountDownLatch or CompletableFuture usually says what you mean more clearly. The Coordination scenarios show those.
Common questions
Does Thread.sleep() release the lock?
No. A sleeping thread keeps every lock it holds. Any thread that needs one of those locks stays BLOCKED until the sleeper wakes up and leaves the synchronized block.
Does wait() release the lock?
Yes. lock.wait() gives up that object's monitor and parks until another thread calls notify() or notifyAll(). To return from wait() it must take the lock back, so it can be briefly BLOCKED.
Why does wait() throw IllegalMonitorStateException?
wait() and notify() need the object's monitor. Call them only inside synchronized (lock) on the same object.
Does other.sleep(1000) put the other thread to sleep?
No. sleep() is static, so it always pauses the thread that calls it.
Verified: this timeline matches a real program, checked in CI on JDK 21 and 25. How we verify. Unclear or wrong? Tell us