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?
If no threads are waiting in the waiting queue, then notify() and notifyAll() have no effect. Before calling the notify() or notifyAll() method of an object, a thread must own the lock of the object. Hence it must be in one of the object's synchronized methods or synchronized block.
Just to summarize we call wait (), notify () or notifyAll method in Java from synchronized method or synchronized block in Java to avoid: 1) IllegalMonitorStateException in Java which will occur if we don't call wait (), notify () or notifyAll () method from synchronized context.
wait() , this call must be placed in synchronized block, otherwise an IllegalMonitorStateException is thrown.
We need to synchronize the shared resources to ensure that at a time only one thread is able to access the shared resource. If an Object is shared by multiple threads then there is need of synchronization in order to avoid the Object's state to be getting corrupted. Synchronization is needed when Object is mutable.
Why does notify
need a lock too?
Imagine this scenario:
synchronized(x){
while(x.count < 4) {
x.wait();
//...
}
}
Imagine now a notify
elsewhere without any lock around it:
//...
println(x.count); // print 3
x.count++;
if(count == 4)
x.notify()
//...
At first glance, the whole sounds to always work as expected.
However, imagine this race condition:
//Thread1 enters here
synchronized(x){
while(x.count < 4) {
//condition is judged true and thread1 is about to wait
//..but..ohh!! Thread2 is prioritized just now !
//Thread2, acting on notify block side, notices that with its current count incrementation,
//count increases to 4 and therefore a notify is sent....
//but...but x is expected to wait now !!! for nothing maybe indefinitely !
x.wait();
//maybe block here indefinitely waiting for a notify that already occurred!
}
}
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 a wait
should never overlap.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With