I was getting java.lang.IllegalMonitorStateException
. I referred this question and it solved my problem. The first answer is
To be able to call notify() you need to synchronize on the same object.
synchronized (someObject) {
someObject.wait();
}
/* different thread / object */
synchronized (someObject) {
someObject.notify();
}
My question is why we need to synchronize on the same object ad how it works?
As far as my understanding goes when we say
synchronized (someObject) {
someObject.wait();
}
we get a lock on object someObject and then we call wait() on it. Now how can another thread get lock on same object to call notify() on it? What am I missing?
Why does
notify
need a lock too?Imagine this scenario:
Imagine now a
notify
elsewhere without any lock around it:At first glance, the whole sounds to always work as expected.
However, imagine this race condition:
If only we had a way to tell this to
notify
side:Thread 1: "Humm..
notify
, you are cute but I've just started to evaluate my condition (x.count < 4
) to true, so please... don't be silly by sending your expected notification just now (before I put my status to waiting), otherwise, I would be ridiculous to wait for a thing that already passed"Thread2: "Ok ok... I will put a lock around my logic in order to stay consistent, so that I send my notification after your wait call releases our shared lock, and thus you will receive this notif, allowing to quit your waiting status ;)"
Thus, always place a lock on the
notify
side, on the same object that is hold by wait, in order to avoid this situation and let the relationship always consistent.=> A logic leading to a
notify
and a logic leading to await
should never overlap.As per the javadoc for Object#wait()
To use wait/notify the thread must have the lock, otherwise IllegalMonitorStateException is thrown
Why
So,
wait()
makes current thread release the locknotify()
signals other waiting thread(s) which then try to acquire the lock.For doing either, the current thread must have the lock. And it makes sense!
Edit
Why must thread calling wait() hold the lock is pretty obvious now.
But why must thread calling notify() hold the lock? Well, for one, to prove its
authenticity
. Otherwise any thread could keep firingfalse notifications
and thewaiting
threads would keep getting interrupted. Thankfully that is not the case.wait/notify are typically used to wait for some other thread to accomplish a task, or to wait until a certain condition is satisfied.
Lets say we have an object called objectA and two threads called thread1 and thread2.
thread1 has some thread safe task,so it acquires objectA's monitor using synchronized block.
In java calling wait() means releasing monitors so that other threads can get this monitor and achieve its tasks and current thread goes into some state called waiting state for objectA's monitor.
Now thread2 can own the objectA's monitor and excutes its task.
Once task completes it notifies the other threads in waiting state that it is released the monitor on the object it owns. please note that to call notify() also thread should be owner of object monitor.
here calling wait() on objectA and calling notify() on other object(lets say objectB) is makes no use to thread1.Since thread1 waiting to get monitor on objectA not on other object(lets say objectB).
update
Why obtain monitor to call notify()
to call notify() we need to obtain monitor,because it is guaranteed that two threads trying to call notify( ) on one object won’t step on each other’s toes(to aviod race condition).
why we need to get lock before notify
Looking through the Hotspot JVM source code I found this: The
notify()
method modifies the wait set of the object's monitor. (The wait set of an object is the set of threads that have calledwait()
on it.) If the access to the wait set was not synchronized bad things could happen: for example a thread could be dropped from the set without ever being awoken. Requiring that the calling thread owns the monitor before callingnotify()
solves this issue, though other solutions could also exist.There are also other arguments, such as notify being called without holding the monitor often implying a programmer error, but I don't think that's enough to motivate such a restriction.