IllegalMonitorStateException on wait call
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
IllegalMonitorStateException on a wait() call means the current thread tried to use an object's monitor methods without owning that object's monitor. In plain Java terms, you can call wait, notify, or notifyAll only while synchronized on the exact same object.
Why the Exception Happens
Every object in Java can act as a monitor. The methods wait(), notify(), and notifyAll() are tied to that monitor, not just to any synchronized block nearby.
This is wrong:
The thread is calling wait() on lock without first entering synchronized (lock), so Java throws IllegalMonitorStateException immediately.
Synchronize on the Same Object You Wait On
The correct pattern is to acquire the monitor of the same object before calling wait().
The same rule applies to notify() and notifyAll(). If you are waiting on lock, you must also notify on lock, and both calls must happen while synchronized on lock.
The Real Pattern Is Condition Waiting
wait() is not meant to be used as a generic sleep replacement. It exists for condition waiting. One thread waits until a shared state changes, and another thread changes the state and notifies waiting threads.
This is the real use case for monitor methods: coordination around shared state.
Always Wait in a Loop
Even after you fix the monitor ownership problem, you still need the standard waiting pattern: check the condition in a while loop, not an if block.
That matters because:
- a thread can wake up without the condition truly being satisfied
- multiple waiting threads can compete after a notification
- the condition may have changed again by the time the thread runs
So this is correct:
and this is fragile:
Common Mix-Ups
One common mistake is synchronizing on one object and calling wait() on another.
That still fails, because owning this does not mean owning lock.
Another mistake is using Thread.sleep() and wait() interchangeably. sleep() pauses the current thread without involving a monitor. wait() releases the monitor and participates in inter-thread coordination.
If your code just needs a delay, use sleep. If it needs signaling between threads, use wait and notify, or better yet, use higher-level concurrency utilities when possible.
Common Pitfalls
The first pitfall is calling wait, notify, or notifyAll outside synchronized. That is the direct cause of IllegalMonitorStateException.
Another issue is synchronizing on the wrong object. The monitor you hold must be the same object whose wait-set methods you invoke.
Developers also often use if instead of while around wait(), which introduces correctness bugs even after the exception is gone.
Finally, modern Java often has better tools such as BlockingQueue, CountDownLatch, or Condition. If the coordination problem is nontrivial, those abstractions are usually easier to reason about than low-level monitor code.
Summary
- '
IllegalMonitorStateExceptionmeans the thread does not own the monitor of the object it calledwait()on.' - Call
wait,notify, andnotifyAllonly insidesynchronizedon the same object. - Use
wait()for condition waiting, not as a generic sleep mechanism. - Always check the wait condition in a
whileloop. - Prefer higher-level concurrency utilities when the coordination logic grows beyond a simple monitor example.

