On Sun, May 31, 2015 at 02:31:25PM +1000, David Holmes wrote:
> >As I recently fell into the trap of forgetting the synchronized block
> >around a single notifyAll(), I believe, the current situation is just
> >errorprone.
> 
> How is it errorprone? You forgot to acquire the lock and you got an
> IllegalMonitorStateException when you did notifyAll. That's pointing
> out your error.


The reason for not making wait/notify synchronized is *not* that "it would be 
unnecessary because you typically already hold the lock anyway". The reason is 
(as David Holms pointed out earlier) that it would be *meaningless* to make 
them synchronized.

When you say it's errorprone it sounds like you first had

    notifyAll();

and then "fixed" the IllegalMonitorStateException by doing

    synchronized (this) {
        notifyAll();
    }

(and then wrote your original email asking why notifyAll didn't do this "on the 
inside").

If this is the case you have not understood the intention of using synchronized 
here. In a nutshell wait and notify is all about thread communication, and for 
that to work correctly you need to synchronize your execution. Let me try to 
explain why wrapping *just* notifyAll() in a synchronized block (or relying on 
making notifyAll synchronized) is broken: Suppose you have a producer / 
consumer thing going on. In produce() you have something like

    enqueue(value);
    synchronized (this) {
        notifyAll(); // because consumer may be waiting for a value
    }
    
and in consume() you have something like

    synchronized (this) {
        while (noValueIsAvailable())
            wait();
    }
    value = retrieve();

Suppose now that ProducerThread enters produce(), enqueues a value and before 
reaching notifyAll, ConsumerThread comes along, enters consume(), consumes the 
value, processes the value, calls consume *again*, sees that noValueIsAvailable 
and calls wait. ProducerThread now continues it's execution and calls 
notifyAll(). ConsumerThread is woken up, but at this point no value is 
available despite there was a call to notify! (In the best case, this doesn't 
crash the program, in worst case, ProducerThread assumed that the value should 
be processed after notifyAll, in which case you may run into a deadlock. If 
there were more variables involved you could also have memory visibility issues 
involved and accidentally break class invariants by doing this.)

I've written an answer to a similar question here:

"Why must wait() always be in synchronized block"
http://stackoverflow.com/a/2779674/276052

best regards,
Andreas

Reply via email to