The Java Memory Model


Published on

Published in: Technology
  • 1) Gosling, not Goslip.
    2) Perhaps it's been said, but detrimental effect JMM had on PMMs performance was shown to be negligible by I think Sarita Adve or one of her students.
    3) According to Bill Pugh, person behind the crusade for new JMM, original JMM was broken and bordered on unimplementable when one wanted to keep all rules in as they were defined.
    4) You might have a typo: If happens-before is defined, reordering at will is PROHIBITED rather than allowed. The paragraph you have on this seems to be missing a 'doesn't' prior to 'exist'.

    With all that said I liked your presentation.
    Are you sure you want to  Yes  No
    Your message goes here

The Java Memory Model

  1. 1. The Java Memory Model<br />Alexander Martens<br />
  2. 2. Structure<br />What is a memory model about?<br />Platform memory models<br />Annotation: Formal semantics<br />Pro & Contra<br />The new Java Memory Model (JMM)<br />History<br />Atomicity rules<br />Ordering rules<br />Visibility rules<br />Piggybacking on synchronization<br />Publication<br />Initialization safety<br />Changes<br />Implementation sketch<br />
  3. 3. What is a memory model about?<br />A memory model defines the behavior of threads how to interact through shared mutual memory.<br />Therefore you need rules for<br />Atomicity: Which operations are atomic?<br />Ordering: In which order do the operations happen?<br />Visibility: When is the modified data visible to other processors?<br />These depends on the memory model at processor level, because of the varying degrees of cache coherence across different architectures.<br />
  4. 4. Platform memory models<br />
  5. 5. Platform memory models<br />defines what guarantees programs can expect from the memory<br />Atomicity: Which operations are not interrupted by the scheduler?<br />Ordering: In which situation are operations reordered to achieve maximum performance?<br />Visibility: Which writes to shared mutual memory are visible to other processors at any given time?<br />specifies memory barriers (special instructions of a processor) to enforce an ordering constraint<br />Some processors exhibit a strong memory model, other processors exhibit a weaker memory model (different processors are able to see different values for the same memory location).<br />
  6. 6. JMM and PMM<br />JMM can be seen as an abstraction layer across different multiprocessor architectures.<br />In dependence to the underlying hardware, the Java compiler deals with the differences by inserting memory barriers at the appropriate places to maintain the rules of the JMM.<br />
  7. 7. Annotation: Formal semantics<br />Together with the definition of single-threaded execution, the memory model specifies the formal semantics of a programming language.<br />Typically, in a single-threaded environment the compiler is required to implement as-if-serial semantics.<br />As-if-serial: All actions of a thread can be reordered for optimization, as long as the result is the same as if they are ordered in program order.<br />
  8. 8. Pro & Contra<br />Pro<br />A programmer can reason about code execution.<br />Atomicity and visibility is well-regulated.<br />A data race can be prevented, because of ordering rules.<br />A data race occurs, if a reads and writes of different threads on the same variable are not in a partial order.<br />A compiler / processor is able to perform important optimizations, like loop fusion, in multi-threaded environment to achieve maximum performance.<br />Contra<br />The memory model also leads to performance cost, because of locks and other communication stuff.<br />
  9. 9. History<br />1991: Oak was developed under the name &quot;The Green Project&quot; by James Goslip and other developers within 18 months. The project was initiated by Sun Microsystems to develop a kernel for executing safe, portable, object-oriented and multi-threaded software on set-top boxes. <br />1995: Java 1.0 has been published by Sun Microsystems.<br />
  10. 10. History<br />2004: The original memory model was updated through the Java Community Process, as Java Specification Request 133, for Java 5.0, because the old one prevented many runtime optimizations and it didn’t provide enough guarantees for code safety.<br />
  11. 11. Atomicity rules<br />Accesses to variables of primitive types (excluding long and double) and reference variables are atomic.<br />Accesses to volatile variables of primitive types (including long and double) and reference variables are atomic.<br />Operations on atomic variables in the package „java.util.concurrent.atomic“ are atomic, too.<br />
  12. 12. Ordering rules<br />JMM defines an happens-before partially order for all instructions in a multi-threaded program.<br />The order guarantees: Thread B will see the result of Thread A, if there exists a happens-before relation between B and A (because of corresponding visibility rules).<br />If there exists a happens-before relation, the order of instructions will be reordered at will.<br />
  13. 13. Happens-before order<br />Program order rule<br />Monitor lock rule<br />Volatile variable rule<br />Thread start rule<br />Thread termination rule<br />Interruption rule<br />Finalizer rule<br />Transitivity<br />
  14. 14. Visibility rules<br />Thread rule<br />Monitor lock rule<br />Volatile variable rule<br />Atomic variable rule<br />Final variable rule<br />
  15. 15. Piggybacking on synchronization<br />Piggybacking on synchronization means combining the program order rule with the monitor lock rule or volatile variable rule concerning ordering and visibility of ordering and visibility, appearing in a code sequence.<br />Pro: <br />Not every method must be synchronized. <br />Performance benefit<br />A global order can be asserted by using a volatile variable as a guard.<br />
  16. 16. Publication<br />The absence of a happens-before order between publishing a shared object and accessing it leads to a partially constructed object.<br />@NotThreadSafe<br />public class UnsafeLazyInitialization{<br /> private static Resource resource;<br /> public static Resource getInstance() {<br />if (resource == null)<br /> resource = new Resource();<br />return resource;<br />}<br />}<br />
  17. 17. Thread-safe lazy initilization<br />Thread-safe lazy initialization is guaranteed by synchronization of the getInstance method.<br />@ThreadSafe<br />public class SafeLazyInitialization{<br /> private static Resource resource;<br /> public synchronized static Resource getInstance() {<br />if (resource == null)<br /> resource = new Resource();<br />return resource;<br />}<br />}<br />
  18. 18. Double-checked locking<br />Antipattern (not thread safe), invented to reduce the impact of synchronization.<br />In the original JMM synchronization was expensive concerning performance.<br />Since JRE 5.0 it’s obsolete, because of a tuned JVM (especially JMM).<br />Now it’s better to use thelazy initialization holder class idiom to gain performance, because it offers the same benefit and is easier to understand.<br />
  19. 19. Double-checked locking<br />@NotThreadSafe<br />public class DoubleCheckedLocking{<br /> private static Resource resource;<br /> public static Resource getInstance() {<br />if (resource == null) {<br /> synchronized (doubleCheckedLocking.class) {<br />if (resource == null) <br /> resource = new Resource();<br />}<br />}<br />}<br />}<br />
  20. 20. Lazy initialization holder class idiom<br />combines the safe lazy initialization with the lazy initialization holder class idiom<br />does not require synchronization, because of eager class initialization idiom<br />@ThreadSafe<br />public class ResourceFactory{<br /> private static class ResourceHolder{<br /> public static Resource resource= new Resource();<br />}<br /> public static Resource getResource() {<br />return ResourceHolder.resource;<br />}<br />}<br />
  21. 21. Initialization safety<br />Allows properly constructed immutable objects to be safely shared across threads without synchronization.<br />Threads, obtaining a reference to that objects, are guaranteed to see up-to-date values of final fields.<br />Initial writes aren’t reordered with accesses, coming after the final field is frozen.<br />
  22. 22. Changes<br />Accesses to volatile variables won’t be reordered with any other memory operation.<br />useful for using a volatile variable as a guard<br />static int a = 0, b = 0;<br />static int x = 0, y = 0;<br />static volatile boolean initialized =false;<br /> <br />//Thread A<br />a = 1;<br />b = 1;<br />initialized =true;<br /> <br />//ThreadB<br />while(!initialized){}<br />x = a;<br />y = b;<br />
  23. 23. Changes<br />Introduction of the happens-before order<br />The initialization of final fields will never be reordered with operations following the finalization associated with the end of the constructor. <br />Final means final.<br />
  24. 24. Implementation sketch<br />Dependent on the underlying hardware platform model , the Java compiler insert the right memory barriers/fences, so that the Java memory model is valid. <br />In a general model, the following fences exist:<br />LoadLoad<br />StoreStore<br />LoadStore<br />StoreLoad<br />
  25. 25. Implementation sketch<br />A synchronized block can be realized as follows:<br />public class X {<br /> private int a,i;<br /> public void synchronized f(){<br />LoadLoad;<br />LoadStore;<br />i= a;<br /> a =i;<br />StoreLoad;<br />StoreStore;<br />}<br />}<br />
  26. 26. Thank you for your attention! Questions?<br />