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.