Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we need to synchronize on the same object for notify() to work

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?

like image 447
Aniket Thakur Avatar asked Aug 07 '13 05:08

Aniket Thakur


People also ask

Why wait () notify () and notifyAll () methods have to be called from a synchronized method or block?

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.

Why wait and notify needs to call from synchronized method?

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.

Can we call wait notify without synchronized?

wait() , this call must be placed in synchronized block, otherwise an IllegalMonitorStateException is thrown.

Why do we need synchronization?

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.


1 Answers

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.

like image 147
Mik378 Avatar answered Sep 22 '22 01:09

Mik378