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