Why isn't Object.notify() a synchronized method?

Andreas Lundblad andreas.lundblad at oracle.com
Wed Jun 3 20:16:07 UTC 2015


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


More information about the hotspot-compiler-dev mailing list