(window.webpackJsonp=window.webpackJsonp||[]).push([[1592],{2001:function(e,t,a){"use strict";a.r(t);var s=a(31),n=Object(s.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"java-memory-model"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#java-memory-model"}},[e._v("#")]),e._v(" Java Memory Model")]),e._v(" "),a("h2",{attrs:{id:"motivation-for-the-memory-model"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#motivation-for-the-memory-model"}},[e._v("#")]),e._v(" Motivation for the Memory Model")]),e._v(" "),a("p",[e._v("Consider the following example:")]),e._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("class")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("Example")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("int")]),e._v(" a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" d"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("void")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("doIt")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n a "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" b "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n c "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" d "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n\n")])])]),a("p",[e._v("If this class is used is a single-threaded application, then the observable behavior will be exactly as you would expect. For instance:")]),e._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("class")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("SingleThreaded")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("static")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("void")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v(" args"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("Example")]),e._v(" eg "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("new")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("Example")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("System")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("out"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("println")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("eg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("a "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('", "')]),e._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" eg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n eg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("doIt")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("System")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("out"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("println")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("eg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("a "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('", "')]),e._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" eg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n\n")])])]),a("p",[e._v("will output:")]),e._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1")]),e._v("\n\n")])])]),a("p",[a("strong",[e._v('As far as the "main" thread can tell')]),e._v(", the statements in the "),a("code",[e._v("main()")]),e._v(" method and the "),a("code",[e._v("doIt()")]),e._v(" method will be executed in the order that they are written in the source code. This is a clear requirement of the Java Language Specification (JLS).")]),e._v(" "),a("p",[e._v("Now consider the same class used in a multi-threaded application.")]),e._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("class")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("MultiThreaded")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("static")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("void")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v(" args"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("final")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("Example")]),e._v(" eg "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("new")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("Example")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("new")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("Thread")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("new")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("Runnable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("void")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("run")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("while")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[e._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n eg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("doIt")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("start")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("while")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[e._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("System")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("out"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("println")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("eg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("a "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[e._v('", "')]),e._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" eg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(".")]),e._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n\n")])])]),a("p",[e._v("What will this print?")]),e._v(" "),a("p",[e._v("In fact, according to the JLS it is not possible to predict that this will print:")]),e._v(" "),a("ul",[a("li",[e._v("You will probably see a few lines of "),a("code",[e._v("0, 0")]),e._v(" to start with.")]),e._v(" "),a("li",[e._v("Then you probably see lines like "),a("code",[e._v("N, N")]),e._v(" or "),a("code",[e._v("N, N + 1")]),e._v(".")]),e._v(" "),a("li",[e._v("You might see lines like "),a("code",[e._v("N + 1, N")]),e._v(".")]),e._v(" "),a("li",[e._v("In theory, you might even see that the "),a("code",[e._v("0, 0")]),e._v(" lines continue forever"),a("sup",[e._v("1")]),e._v(".")])]),e._v(" "),a("p",[a("sup",[e._v("1 - In practice the presence of the "),a("code",[e._v("println")]),e._v(" statements is liable to cause some serendipitous synchronization and memory cache flushing. That is likely to hide some of the effects that would cause the above behavior.")])]),e._v(" "),a("p",[e._v("So how can we explain these?")]),e._v(" "),a("h3",{attrs:{id:"reordering-of-assignments"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#reordering-of-assignments"}},[e._v("#")]),e._v(" Reordering of assignments")]),e._v(" "),a("p",[e._v("One possible explanation for unexpected results is that the JIT compiler has changed the order of the assignments in the "),a("code",[e._v("doIt()")]),e._v(" method. The JLS requires that statements "),a("strong",[e._v("appear to")]),e._v(" execute in order "),a("strong",[e._v("from the perspective of the current")]),e._v(" thread. In this case, nothing in the code of the "),a("code",[e._v("doIt()")]),e._v(" method can observe the effect of a (hypothetical) reordering of those two statement. This means that the JIT compiler would be permitted to do that.")]),e._v(" "),a("p",[e._v("Why would it do that?")]),e._v(" "),a("p",[e._v("On typical modern hardware, machine instructions are executed using a instruction pipeline which allows a sequence of instructions to be in different stages. Some phases of instruction execution take longer than others, and memory operations tend to take a longer time. A smart compiler can optimize the instruction throughput of the pipeline by ordering the instructions to maximize the amount of overlap. This may lead to executing parts of statements out of order. The JLS permits this provided that not affect the result of the computation "),a("strong",[e._v("from the perspective of the current thread")]),e._v(".")]),e._v(" "),a("h3",{attrs:{id:"effects-of-memory-caches"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#effects-of-memory-caches"}},[e._v("#")]),e._v(" Effects of memory caches")]),e._v(" "),a("p",[e._v("A second possible explanation is effect of memory caching. In a classical computer architecture, each processor has a small set of registers, and a larger amount of memory. Access to registers is much faster than access to main memory. In modern architectures, there are memory caches that are slower than registers, but faster than main memory.")]),e._v(" "),a("p",[e._v("A compiler will exploit this by trying to keep copies of variables in registers, or in the memory caches. If a variable does not "),a("strong",[e._v("need")]),e._v(" to be flushed to main memory, or does not "),a("strong",[e._v("need")]),e._v(' to be read from memory, there are significant performance benefits in not doing this. In cases where the JLS does not require memory operations to be visible to another thread, the Java JIT compiler is likely to not add the "read barrier" and "write barrier" instructions that will force main memory reads and writes. Once again, the performance benefits of doing this are significant.')]),e._v(" "),a("h3",{attrs:{id:"proper-synchronization"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#proper-synchronization"}},[e._v("#")]),e._v(" Proper synchronization")]),e._v(" "),a("p",[e._v("So far, we have seen that the JLS allows the JIT compiler to generate code that makes single-threaded code faster by reordering or avoiding memory operations. But what happens when other threads can observe the state of the (shared) variables in main memory?")]),e._v(" "),a("p",[e._v("The answer is, that the other threads are liable to observe variable states which would appear to be impossible ... based on the code order of the Java statements. The solution to this is to use appropriate synchronization. The three main approaches are:")]),e._v(" "),a("ul",[a("li",[e._v("Using primitive mutexes and the "),a("code",[e._v("synchronized")]),e._v(" constructs.")]),e._v(" "),a("li",[e._v("Using "),a("code",[e._v("volatile")]),e._v(" variables.")]),e._v(" "),a("li",[e._v("Using higher level concurrency support; e.g. classes in the "),a("code",[e._v("java.util.concurrent")]),e._v(" packages.")])]),e._v(" "),a("p",[e._v("But even with this, it is important to understand where synchronization is needed, and what effects that you can rely on. This is where the Java Memory Model comes in.")]),e._v(" "),a("h3",{attrs:{id:"the-memory-model"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#the-memory-model"}},[e._v("#")]),e._v(" The Memory Model")]),e._v(" "),a("p",[e._v("The Java Memory Model is the section of the JLS that specifies the conditions under which one thread is guaranteed to see the effects of memory writes made by another thread. The Memory Model is specified with a fair degree of "),a("strong",[e._v("formal rigor")]),e._v(', and (as a result) requires detailed and careful reading to understand. But the basic principle is that certain constructs create a "happens-before" relation between write of a variable by one thread, and a subsequent read of the same variable by another thread. If the "happens before" relation exists, the JIT compiler is '),a("strong",[e._v("obliged")]),e._v(" to generate code that will ensure that the read operation sees the value written by the write.")]),e._v(" "),a("p",[e._v("Armed with this, it is possible to reason about memory coherency in a Java program, and decide whether this will be predictable and consistent for "),a("strong",[e._v("all")]),e._v(" execution platforms.")]),e._v(" "),a("h2",{attrs:{id:"happens-before-relationships"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#happens-before-relationships"}},[e._v("#")]),e._v(" Happens-before relationships")]),e._v(" "),a("p",[e._v("(The following is a simplified version of what the Java Language Specification says. For a deeper understanding, you need to read the specification itself.)")]),e._v(" "),a("p",[e._v("Happens-before relationships are the part of the Memory Model that allow us to understand and reason about memory visibility. As the JLS says ("),a("a",{attrs:{href:"https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5",target:"_blank",rel:"noopener noreferrer"}},[e._v("JLS 17.4.5"),a("OutboundLink")],1),e._v("):")]),e._v(" "),a("blockquote"),e._v(" "),a("p",[e._v('"Two '),a("strong",[e._v("actions")]),e._v(" can be ordered by a "),a("strong",[e._v("happens-before")]),e._v(" relationship. If one action "),a("strong",[e._v("happens-before")]),e._v(' another, then the first is visible to and ordered before the second."')]),e._v(" "),a("p",[e._v("What does this mean?")]),e._v(" "),a("h3",{attrs:{id:"actions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#actions"}},[e._v("#")]),e._v(" Actions")]),e._v(" "),a("p",[e._v("The actions that the above quote refers to are specified in "),a("a",{attrs:{href:"https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.2",target:"_blank",rel:"noopener noreferrer"}},[e._v("JLS 17.4.2"),a("OutboundLink")],1),e._v(". There are 5 kinds of action listed defined by the spec:")]),e._v(" "),a("li",[e._v("\nRead: Reading a non-volatile variable.\n")]),e._v(" "),a("li",[e._v("\nWrite: Writing a non-volatile variable.\n")]),e._v(" "),a("li",[e._v("\nSynchronization actions:\n"),a("ul",[a("li",[e._v("\nVolatile read: Reading a volatile variable.\n")]),e._v(" "),a("li",[e._v("\nVolatile write: Writing a volatile variable.\n")]),e._v(" "),a("li",[e._v("\nLock. Locking a monitor\n")]),e._v(" "),a("li",[e._v("\nUnlock. Unlocking a monitor.\n")]),e._v(" "),a("li",[e._v("\nThe (synthetic) first and last actions of a thread.\n")]),e._v(" "),a("li",[e._v("\nActions that start a thread or detect that a thread has terminated.\n")]),e._v(" "),a("p",[e._v("External Actions. An action that has a result that depends on the environment in which the program.")]),e._v(" "),a("p",[e._v("Thread divergence actions. These model the behavior of certain kinds of infinite loop.")]),e._v(" "),a("h3",{attrs:{id:"program-order-and-synchronization-order"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#program-order-and-synchronization-order"}},[e._v("#")]),e._v(" Program Order and Synchronization Order")]),e._v(" "),a("p",[e._v("These two orderings ( "),a("a",{attrs:{href:"https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.3",target:"_blank",rel:"noopener noreferrer"}},[e._v("JLS 17.4.3"),a("OutboundLink")],1),e._v(" and "),a("a",{attrs:{href:"https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.4",target:"_blank",rel:"noopener noreferrer"}},[e._v("JLS 17.4.4"),a("OutboundLink")],1),e._v(" ) govern the execution of statements in a Java")]),e._v(" "),a("p",[e._v("Program order describes the order of statement execution within a single thread.")]),e._v(" "),a("p",[e._v("Synchronization order describes the order of statement execution for two statements connected by a synchronization:")]),e._v(" "),a("li",[e._v("\nAn unlock action on monitor **synchronizes-with** all subsequent lock actions on that monitor.\n")]),e._v(" "),a("li",[e._v("\nA write to a volatile variable **synchronizes-with** all subsequent reads of the same variable by any thread.\n")]),e._v(" "),a("li",[e._v("\nAn action that starts a thread (i.e. the call to `Thread.start()`) **synchronizes-with** the first action in the thread it starts (i.e. the call to the thread's `run()` method).\n")]),e._v(" "),a("li",[e._v("\nThe default initialization of fields **synchronizes-with** the first action in every thread. (See the JLS for an explanation of this.)\n")]),e._v(" "),a("li",[e._v("\nThe final action in a thread **synchronizes-with** any action in another thread that detects the termination; e.g. the return of a `join()` call or `isTerminated()` call that returns `true`.\n")]),e._v(" "),a("li",[e._v("\nIf one thread interrupts another thread, the interrupt call in the first thread **synchronizes-with** the point where another thread detects that the thread was interrupted.\n")]),e._v(" "),a("h3",{attrs:{id:"happens-before-order"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#happens-before-order"}},[e._v("#")]),e._v(" Happens-before Order")]),e._v(" "),a("p",[e._v("This ordering ( "),a("a",{attrs:{href:"https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5",target:"_blank",rel:"noopener noreferrer"}},[e._v("JLS 17.4.5"),a("OutboundLink")],1),e._v(" ) is what determines whether a memory write is guaranteed to be visible to a subsequent memory read.")]),e._v(" "),a("p",[e._v("More specifically, a read of a variable "),a("code",[e._v("v")]),e._v(" is guaranteed to observe a write to "),a("code",[e._v("v")]),e._v(" if and only if "),a("code",[e._v("write(v)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("read(v)")]),e._v(" AND there is no intervening write to "),a("code",[e._v("v")]),e._v(". If there are intervening writes, then the "),a("code",[e._v("read(v)")]),e._v(" may see the results of them rather than the earlier one.")]),e._v(" "),a("p",[e._v("The rules that define the "),a("strong",[e._v("happens-before")]),e._v(" ordering are as follows:")]),e._v(" "),a("li",[e._v("\n**Happens-Before Rule #1** - If x and y are actions of the same thread and x comes before y in **program order**, then x **happens-before** y.\n")]),e._v(" "),a("li",[e._v("\n**Happens-Before Rule #2** - There is a happens-before edge from the end of a constructor of an object to the start of a finalizer for that object.\n")]),e._v(" "),a("li",[e._v("\n**Happens-Before Rule #3** - If an action x **synchronizes-with** a subsequent action y, then x **happens-before** y.\n")]),e._v(" "),a("li",[e._v("\n**Happens-Before Rule #4** - If x **happens-before** y and y **happens-before** z then x **happens-before** z.\n")]),e._v(" "),a("p",[e._v("In addition, various classes in the Java standard libraries are specified as defining "),a("strong",[e._v("happens-before")]),e._v(" relationships. You can interpret this as meaning that it happens "),a("strong",[e._v("somehow")]),e._v(", without needing to know exactly how the guarantee is going to be met.")]),e._v(" "),a("h2",{attrs:{id:"happens-before-reasoning-applied-to-some-examples"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#happens-before-reasoning-applied-to-some-examples"}},[e._v("#")]),e._v(" Happens-before reasoning applied to some examples")]),e._v(" "),a("p",[e._v("We will present some examples to show how to apply "),a("strong",[e._v("happens-before")]),e._v(" reasoning to check that writes are visible to subsequent reads.")]),e._v(" "),a("h3",{attrs:{id:"single-threaded-code"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#single-threaded-code"}},[e._v("#")]),e._v(" Single-threaded code")]),e._v(" "),a("p",[e._v("As you would expect, writes are always visible to subsequent reads in a single-threaded program.")]),e._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("class")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("SingleThreadExample")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("int")]),e._v(" a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("int")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("add")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n a "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// write(a)")]),e._v("\n b "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// write(b)")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("return")]),e._v(" a "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// read(a) followed by read(b)")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n\n")])])]),a("p",[e._v("By Happens-Before Rule #1:")]),e._v(" "),a("ol",[a("li",[e._v("The "),a("code",[e._v("write(a)")]),e._v(" action "),a("strong",[e._v("happens-before")]),e._v(" the "),a("code",[e._v("write(b)")]),e._v(" action.")]),e._v(" "),a("li",[e._v("The "),a("code",[e._v("write(b)")]),e._v(" action "),a("strong",[e._v("happens-before")]),e._v(" the "),a("code",[e._v("read(a)")]),e._v(" action.")]),e._v(" "),a("li",[e._v("The "),a("code",[e._v("read(a)")]),e._v(" action "),a("strong",[e._v("happens-before")]),e._v(" the "),a("code",[e._v("read(a)")]),e._v(" action.")])]),e._v(" "),a("p",[e._v("By Happens-Before Rule #4:")]),e._v(" "),a("ol",[a("li",[a("code",[e._v("write(a)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("write(b)")]),e._v(" AND "),a("code",[e._v("write(b)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("read(a)")]),e._v(" IMPLIES "),a("code",[e._v("write(a)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("read(a)")]),e._v(".")]),e._v(" "),a("li",[a("code",[e._v("write(b)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("read(a)")]),e._v(" AND "),a("code",[e._v("read(a)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("read(b)")]),e._v(" IMPLIES "),a("code",[e._v("write(b)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("read(b)")]),e._v(".")])]),e._v(" "),a("p",[e._v("Summing up:")]),e._v(" "),a("ol",[a("li",[e._v("The "),a("code",[e._v("write(a)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("read(a)")]),e._v(" relation means that the "),a("code",[e._v("a + b")]),e._v(" statement is guaranteed to see the correct value of "),a("code",[e._v("a")]),e._v(".")]),e._v(" "),a("li",[e._v("The "),a("code",[e._v("write(b)")]),e._v(" "),a("strong",[e._v("happens-before")]),e._v(" "),a("code",[e._v("read(b)")]),e._v(" relation means that the "),a("code",[e._v("a + b")]),e._v(" statement is guaranteed to see the correct value of "),a("code",[e._v("b")]),e._v(".")])]),e._v(" "),a("h3",{attrs:{id:"behavior-of-volatile-in-an-example-with-2-threads"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#behavior-of-volatile-in-an-example-with-2-threads"}},[e._v("#")]),e._v(" Behavior of 'volatile' in an example with 2 threads")]),e._v(" "),a("p",[e._v("We will use the following example code to explore some implications of the Memory Model for `volatile.")]),e._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("class")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[e._v("VolatileExample")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("private")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("volatile")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("int")]),e._v(" a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("private")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("int")]),e._v(" b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// NOT volatile")]),e._v("\n \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("void")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("update")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("int")]),e._v(" first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("int")]),e._v(" second"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n b "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// write(b)")]),e._v("\n a "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" second"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// write-volatile(a)")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("public")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("int")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("observe")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("return")]),e._v(" a "),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("+")]),e._v(" b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// read-volatile(a) followed by read(b)")]),e._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n\n")])])]),a("p",[e._v("First, consider the following sequence of statements involving 2 threads:")]),e._v(" "),a("ol",[a("li",[e._v("A single instance of "),a("code",[e._v("VolatileExample")]),e._v(" is created; call it "),a("code",[e._v("ve")]),e._v(",")]),e._v(" "),a("li",[a("code",[e._v("ve.update(1, 2)")]),e._v(" is called in one thread, and")]),e._v(" "),a("li",[a("code",[e._v("ve.observe()")]),e._v(" is called in another thread.")])]),e._v(" "),a("p",[e._v("By Happens-Before Rule #1:")]),e._v(" "),a("ol",[a("li",[e._v("The "),a("code",[e._v("write(a)")]),e._v(" action "),a("strong",[e._v("happens-before")]),e._v(" the "),a("code",[e._v("volatile-write(a)")]),e._v(" action.")]),e._v(" "),a("li",[e._v("The "),a("code",[e._v("volatile-read(a)")]),e._v(" action "),a("strong",[e._v("happens-before")]),e._v(" the "),a("code",[e._v("read(b)")]),e._v(" action.")])]),e._v(" "),a("p",[e._v("By Happens-Before Rule #2:")]),e._v(" "),a("ol",[a("li",[e._v("The "),a("code",[e._v("volatile-write(a)")]),e._v(" action in the first thread "),a("strong",[e._v("happens-before")]),e._v(" the "),a("code",[e._v("volatile-read(a)")]),e._v(" action in the second thread.")])]),e._v(" "),a("p",[e._v("By Happens-Before Rule #4:")]),e._v(" "),a("ol",[a("li",[e._v("The "),a("code",[e._v("write(b)")]),e._v(" action in the first thread "),a("strong",[e._v("happens-before")]),e._v(" the "),a("code",[e._v("read(b)")]),e._v(" action in the second thread.")])]),e._v(" "),a("p",[e._v("In other words, for this particular sequence, we are guaranteed that the 2nd thread will see the update to the non-volatile variable "),a("code",[e._v("b")]),e._v(" made by the first thread. However, it is should also be clear that if the assignments in the "),a("code",[e._v("update")]),e._v(" method were the other way around, or the "),a("code",[e._v("observe()")]),e._v(" method read the variable "),a("code",[e._v("b")]),e._v(" before "),a("code",[e._v("a")]),e._v(", then the "),a("strong",[e._v("happens-before")]),e._v(" chain would be broken. The chain would also be broken if "),a("code",[e._v("volatile-read(a)")]),e._v(" in the second thread was not subsequent to the "),a("code",[e._v("volatile-write(a)")]),e._v(" in the first thread.")]),e._v(" "),a("p",[e._v("When the chain is broken, there is no "),a("strong",[e._v("guarantee")]),e._v(" that "),a("code",[e._v("observe()")]),e._v(" will see the correct value of "),a("code",[e._v("b")]),e._v(".")]),e._v(" "),a("h3",{attrs:{id:"volatile-with-three-threads"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#volatile-with-three-threads"}},[e._v("#")]),e._v(" Volatile with three threads")]),e._v(" "),a("p",[e._v("Suppose we to add a third thread into the previous example:")]),e._v(" "),a("ol",[a("li",[e._v("A single instance of "),a("code",[e._v("VolatileExample")]),e._v(" is created; call it "),a("code",[e._v("ve")]),e._v(",\n")]),a("li",[e._v("Two threads call "),a("code",[e._v("update")]),e._v(":\n"),a("ul")]),e._v(" "),a("li",[a("code",[e._v("ve.update(1, 2)")]),e._v(" is called in one thread,")]),e._v(" "),a("li",[a("code",[e._v("ve.update(3, 4)")]),e._v(" is called in the second thread,\n")])])])]),e._v(" "),a("li",[a("code",[e._v("ve.observe()")]),e._v(" is subsequently called in a third thread.")]),e._v(" "),a("p",[e._v("To analyse this completely, we need to consider all of the possible interleavings of the statements in thread one and thread two. Instead, we will consider just two of them.")]),e._v(" "),a("p",[e._v("Scenario #1 - suppose that "),a("code",[e._v("update(1, 2)")]),e._v(" precedes "),a("code",[e._v("update(3,4)")]),e._v(" we get this sequence:")]),e._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[e._v("write")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" write"),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("-")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("volatile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// first thread")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("write")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" write"),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("-")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("volatile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// second thread")]),e._v("\nread"),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("-")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("volatile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("read")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// third thread")]),e._v("\n\n")])])]),a("p",[e._v("In this case, it is easy to see that there is an unbroken "),a("strong",[e._v("happens-before")]),e._v(" chain from "),a("code",[e._v("write(b, 3)")]),e._v(" to "),a("code",[e._v("read(b)")]),e._v(". Furthermore there is no intervening write to "),a("code",[e._v("b")]),e._v(". So, for this scenario, the third thread is guaranteed to see "),a("code",[e._v("b")]),e._v(" as having value "),a("code",[e._v("3")]),e._v(".")]),e._v(" "),a("p",[e._v("Scenario #2 - suppose that "),a("code",[e._v("update(1, 2)")]),e._v(" and "),a("code",[e._v("update(3,4)")]),e._v(" overlap and the ations are interleaved as follows:")]),e._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[e._v("write")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// second thread")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("write")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// first thread")]),e._v("\nwrite"),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("-")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("volatile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// first thread")]),e._v("\nwrite"),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("-")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("volatile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// second thread")]),e._v("\nread"),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("-")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("volatile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(",")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("read")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("b"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("// third thread")]),e._v("\n\n")])])]),a("p",[e._v("Now, while there is a "),a("strong",[e._v("happens-before")]),e._v(" chain from "),a("code",[e._v("write(b, 3)")]),e._v(" to "),a("code",[e._v("read(b)")]),e._v(", there is an intervening "),a("code",[e._v("write(b, 1)")]),e._v(" action performed by the other thread. This means we cannot be certain which value "),a("code",[e._v("read(b)")]),e._v(" will see.")]),e._v(" "),a("p",[e._v("(Aside: This demonstrates that we cannot rely on "),a("code",[e._v("volatile")]),e._v(" for ensuring visibility of non-volatile variables, except in very limited situations.)")]),e._v(" "),a("h2",{attrs:{id:"how-to-avoid-needing-to-understand-the-memory-model"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-to-avoid-needing-to-understand-the-memory-model"}},[e._v("#")]),e._v(" How to avoid needing to understand the Memory Model")]),e._v(" "),a("p",[e._v("The Memory Model is difficult to understand, and difficult to apply. It is useful if you need to reason about the correctness of multi-threaded code, but you do not want to have to do this reasoning for every multi-threaded application that you write.")]),e._v(" "),a("p",[e._v("If you adopt the following principals when writing concurrent code in Java, you can "),a("strong",[e._v("largely")]),e._v(" avoid the need to resort to "),a("strong",[e._v("happens-before")]),e._v(" reasoning.")]),e._v(" "),a("li",[e._v("\nUse immutable data structures where possible. A properly implemented immutable class will be thread-safe, and will not introduce thread-safety issues when you use it with other classes.\n")]),e._v(" "),a("li",[e._v('\nUnderstand and avoid "unsafe publication".\n')]),e._v(" "),a("li",[e._v("\nUse primitive mutexes or `Lock` objects to synchronize access to state in mutable objects that need to be thread-safe"),a("sup",[e._v("1")]),e._v(".\n")]),e._v(" "),a("li",[e._v("\nUse `Executor` / `ExecutorService` or the fork join framework rather than attempting to create manage threads directly.\n")]),e._v(" "),a("li",[e._v("\nUse the `java.util.concurrent classes that provide advanced locks, semaphores, latches and barriers, instead of using wait/notify/notifyAll directly.\n")]),e._v(" "),a("li",[e._v("\nUse the `java.util.concurrent` versions of maps, sets, lists, queues and deques rather than external synchonization of non-concurrent collections.\n")]),e._v(" "),a("p",[e._v('The general principle is to try to use Java\'s built-in concurrency libraries rather than "rolling your own" concurrency. You can rely on them working, if you use them properly.')]),e._v(" "),a("p",[a("sup",[e._v("1 - Not all objects need to be thread safe. For example, if an object or objects is "),a("strong",[e._v("thread-confined")]),e._v(" (i.e. it is only accessible to one thread), then its thread-safety is not relevant.")])]),e._v(" "),a("h4",{attrs:{id:"remarks"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#remarks"}},[e._v("#")]),e._v(" Remarks")]),e._v(" "),a("p",[e._v('The Java Memory Model is the section of the JLS that specifies the conditions under which one thread is guaranteed to see the effects of memory writes made by another thread. The relevant section in recent editions is "JLS 17.4 Memory Model" (in '),a("a",{attrs:{href:"https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4",target:"_blank",rel:"noopener noreferrer"}},[e._v("Java 8"),a("OutboundLink")],1),e._v(", "),a("a",{attrs:{href:"https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4",target:"_blank",rel:"noopener noreferrer"}},[e._v("Java 7"),a("OutboundLink")],1),e._v(", "),a("a",{attrs:{href:"https://docs.oracle.com/javase/specs/jls/se6/html/memory.html#17.4",target:"_blank",rel:"noopener noreferrer"}},[e._v("Java 6"),a("OutboundLink")],1),e._v(")")]),e._v(" "),a("p",[e._v("There was a major overhaul of the Java Memory Model in Java 5 which (among other things) changed the way that "),a("code",[e._v("volatile")]),e._v(" worked. Since then, the memory model been essentially unchanged.")])])}),[],!1,null,null,null);t.default=n.exports}}]);