Note that Doug' Lea's JMM cookbook is written for implementors of JDKs and 
related libraries and JITs, NOT for users of those JDKs and libraries. It 
says so right in the title. It describes rules that would result in a 
*sufficient* implementation of the JMM but is not useful for deducing the 
*required 
or expected *behavior of all JMM implementations. Most JMM implementations 
go beyond the cookbook rules in at least some places and apply 
JMM-valid transformations that are not included in it and can be viewed as 
"shortcuts" that bypass some of the rules in the cookbook. There are many 
examples of this in practice. Lock coarsening and lock biasing 
optimizations are two good example sets.

This means that you need to read the cookbook very carefully, and 
(specifically) that you should not interpret it as a promise of what the 
relationships between various operations are guaranteed to be. If you use 
the cookbook for the latter, your code will break.


Putting aside the current under-the-hood implementations of monitor 
enter/exit and of ReentrantLock (which may and will change), the 
requirements are clear:

from 
e.g. 
https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/locks/ReentrantLock.html:

"A reentrant mutual exclusion Lock 
<https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/locks/Lock.html>
 with 
the same basic behavior and semantics as the implicit monitor lock accessed 
using synchronized methods and statements, but with extended capabilities."


from 
e.g. 
https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/locks/Lock.html:

"Memory Synchronization

All Lock implementations *must* enforce the same memory synchronization 
semantics as provided by the built-in monitor lock, as described in Chapter 
17 of The Java™ Language Specification 
<https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4>:


   - A successful lock operation has the same memory synchronization 
      effects as a successful *Lock* action.
      - A successful unlock operation has the same memory synchronization 
      effects as a successful *Unlock* action.
   
Unsuccessful locking and unlocking operations, and reentrant 
locking/unlocking operations, do not require any memory synchronization 
effects."


So based on the spec, I'd say that you cannot make any assumptions about 
semantic differences between ReentrantLock and synchronized blocks (even if 
you find current implementation differences).

On Wednesday, May 16, 
>
> Hi guys!
>
> probably this one should be more a concurrency-interest question, but I'm 
> sure that's will fit with most of the people around here as well :)
> I was looking to how ReentrantLock and synchronized are different from a 
> semantic point of view and I've found (there are no experimental proofs on 
> my side TBH) something interesting on the 
> http://gee.cs.oswego.edu/dl/jmm/cookbook.html. 
> It seems to me that:
>
> normal store;
> monitorEnter;
> [mutual exclusion zone]
> monitorExit;
> ....
>
> is rather different from a:
>
> normal store;
> (loop of...)
> volatile load
> volatile store (=== CAS)
> ---
> [mutual exclusion zone]
> volatile store
>
> With the former to represent a synchronized block and the latter a spin 
> lock acquisition and release, both with a normal store on top.
> From anyone coming from other worlds than the JVM i suppose that the 
> volatile load could be translated as a load acquire, while the volatile 
> store as a sequential consistent store.
>
> About the monitorEnter/Exit that's more difficult to find something that 
> fit other known memory models (C++) and that's the reason of my request :) 
> From the point of view of the compiler guarantees seems that a normal 
> store (ie any store release as well) preceding monitorEnter could be moved 
> inside the mutual exclusion zone (past the monitorEnter), because the 
> compiler isn't enforcing 
> any memory barrier between them, while with the current implementation of 
> a j.u.c. lock that's can't happen.
> That's the biggest difference I could spot on them, but I'm struggling to 
> find anything (beside looking at the JVM source code) that observe/trigger 
> such compiler re-ordering.
> What do you think about this? I'm just worried of something that actually 
> isn't implemented/isn't happening on any known JVM implementation?
>

AFAIK Most JVM implementations will absolutely do this for monitors and 
will commonly re-order to move stores and loads that precede a monitor 
enter such that they execute after the monitor enter (but before the 
associated monitor exit). Most forms of lock coarsening will have this 
effect in actual emitted code (that any cpu will then see, regardless of 
architecture and CPU memory model). In addition, lock biasing optimizations 
(on monitors) will often result in emitted code that does not enforce a 
storestore or loadstore order between the monitor enter and preceding loads 
or stores on some architectures, allowing the processor to reorder that 
(biased to this thread) monitor enter operation (and potentially some 
operations that follow) with prior loads and stores.

The exact same optimizations would be valid to do for ReentrantLock (since 
per the spec, it shares the same memory ordering semantics requirements), 
but I think that in (currently) practice there are fewer JIT optimizations 
applied to ReentrantLock than to monitor enter/exit.
 

>
> Thanks,
> Franz
>

-- 
You received this message because you are subscribed to the Google Groups 
"mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to