changeset 352:87229545b408

jcstress-samples: lots of memory model and concurrency samples.
author shade
date Sat, 21 Jan 2017 14:04:07 +0100
parents d561a2727cb1
children ce2bd6a0a24d
files jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_01_Simple.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_02_Arbiters.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_03_Termination.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_04_Nesting.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_05_SharedMetadata.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_06_Descriptions.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/ConcurrencySample_01_OperationAtomicity.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/ConcurrencySample_02_ConcurrentHashMap.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_01_Simple.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_02_Arbiters.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_03_Termination.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_04_Nesting.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_05_SharedMetadata.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_06_Descriptions.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_01_AccessAtomicity.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_02_WordTearing.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_03_Coherence.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_04_PartialOrder.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_05_TotalOrder.java jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_06_Finals.java
diffstat 20 files changed, 2012 insertions(+), 435 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_01_Simple.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.IntResult2;
+
+/*
+    This is our first concurrency test. It is deliberately simplistic to show
+    testing approaches, introduce JCStress APIs, etc.
+
+    Suppose we want to see if the field increment is atomic. We can make test
+    with two actors, both actors incrementing the field and recording what
+    value they observed into the result object. As JCStress runs, it will
+    invoke these methods on the objects holding the field once per each actor
+    and instance, and record what results are coming from there.
+
+    Done enough times, we will get the history of observed results, and that
+    would tell us something about the concurrent behavior. For example, running
+    this test would yield:
+
+          [OK] o.o.j.t.JCStressSample_01_Simple
+        (JVM args: [-server])
+      Observed state   Occurrences   Expectation  Interpretation
+                1, 1    54,734,140    ACCEPTABLE  Both threads came up with the same value: atomicity failure.
+                1, 2    47,037,891    ACCEPTABLE  actor1 incremented, then actor2.
+                2, 1    53,204,629    ACCEPTABLE  actor2 incremented, then actor1.
+
+     How to run this test:
+       $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_01_Simple
+ */
+
+// Mark the class as JCStress test.
+@JCStressTest
+
+// These are the test outcomes.
+@Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
+@Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
+@Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
+
+// This is a state object
+@State
+public class APISample_01_Simple {
+
+    int v;
+
+    @Actor
+    public void actor1(IntResult2 r) {
+        r.r1 = ++v; // record result from actor1 to field r1
+    }
+
+    @Actor
+    public void actor2(IntResult2 r) {
+        r.r2 = ++v; // record result from actor2 to field r2
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_02_Arbiters.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.IntResult1;
+
+/*
+    Another flavor of the same test as JCStress_APISample_01_Simple is using
+    arbiters. Arbiters run after both actors, and therefore can observe the
+    final result.
+
+    This allows to directly observe the atomicity failure:
+
+          [OK] org.openjdk.jcstress.samples.JCStress_APISample_02_Arbiters
+        (JVM args: [-server])
+      Observed state   Occurrences              Expectation  Interpretation
+                   1       940,359   ACCEPTABLE_INTERESTING  One update lost: atomicity failure.
+                   2   168,950,601               ACCEPTABLE  Actors updated independently.
+
+    How to run this test:
+       $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_02_Arbiters
+ */
+
+@JCStressTest
+
+// These are the test outcomes.
+@Outcome(id = "1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "One update lost: atomicity failure.")
+@Outcome(id = "2", expect = Expect.ACCEPTABLE, desc = "Actors updated independently.")
+@State
+public class APISample_02_Arbiters {
+
+    int v;
+
+    @Actor
+    public void actor1() {
+        v++;
+    }
+
+    @Actor
+    public void actor2() {
+        v++;
+    }
+
+    @Arbiter
+    public void arbiter(IntResult1 r) {
+        r.r1 = v;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_03_Termination.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+
+/*
+    Some concurrency tests are not following the "run continously" pattern. One
+    of interesting test groups is that asserts if the code had terminated after
+    a signal.
+
+    Here, we use a single @Actor that busy-waits on a field, and a @Signal that
+    sets that field. JCStress would start actor, and then deliver the signal.
+    If it exits in reasonable time, it will record "TERMINATED" result, otherwise
+    record "STALE".
+
+    How to run this test:
+       $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_03_Termination
+ */
+
+@JCStressTest(Mode.Termination)
+@Outcome(id = "TERMINATED", expect = Expect.ACCEPTABLE, desc = "Gracefully finished.")
+@Outcome(id = "STALE", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Test hung up.")
+@State
+public class APISample_03_Termination {
+
+    int v;
+
+    @Actor
+    public void actor1() {
+        while (v == 0) {
+            // spin
+        }
+    }
+
+    @Signal
+    public void signal() {
+        v = 1;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_04_Nesting.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.IntResult2;
+
+/*
+    It is sometimes convenient to put the tests in the same source file for
+    better comparison. JCStress allows to nest tests like this:
+
+    How to run this test:
+       $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_04_Nesting
+ */
+
+public class APISample_04_Nesting {
+
+    @JCStressTest
+    @Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
+    @Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
+    @Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
+    @State
+    public static class PlainTest {
+        int v;
+
+        @Actor
+        public void actor1(IntResult2 r) {
+            r.r1 = ++v;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            r.r2 = ++v;
+        }
+    }
+
+    @JCStressTest
+    @Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
+    @Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
+    @Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
+    @State
+    public static class VolatileTest {
+        volatile int v;
+
+        @Actor
+        public void actor1(IntResult2 r) {
+            r.r1 = ++v;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            r.r2 = ++v;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_05_SharedMetadata.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.IntResult2;
+
+/*
+   In many cases, tests share the outcomes and other metadata. To common them,
+   there is a special @JCStressMeta annotation that says to look up the metadata
+   at another class.
+
+   How to run this test:
+      $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_05_SharedMetadata
+ */
+
+@Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
+@Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
+@Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
+public class APISample_05_SharedMetadata {
+
+    @JCStressTest
+    @JCStressMeta(APISample_05_SharedMetadata.class)
+    @State
+    public static class PlainTest {
+        int v;
+
+        @Actor
+        public void actor1(IntResult2 r) {
+            r.r1 = ++v;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            r.r2 = ++v;
+        }
+    }
+
+    @JCStressTest
+    @JCStressMeta(APISample_05_SharedMetadata.class)
+    @State
+    public static class VolatileTest {
+        volatile int v;
+
+        @Actor
+        public void actor1(IntResult2 r) {
+            r.r1 = ++v;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            r.r2 = ++v;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/APISample_06_Descriptions.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.IntResult2;
+
+/*
+    JCStress also allows to put the descriptions and references right at the test.
+    This helps to identify the goal for the test, as well as the discussions about
+    the behavior in question.
+
+   How to run this test:
+      $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_06_Descriptions
+ */
+
+@JCStressTest
+
+// Optional test description
+@Description("Sample Hello World test")
+
+// Optional references. @Ref is repeatable.
+@Ref("http://openjdk.java.net/projects/code-tools/jcstress/")
+
+@Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
+@Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
+@Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
+@State
+public class APISample_06_Descriptions {
+
+    int v;
+
+    @Actor
+    public void actor1(IntResult2 r) {
+        r.r1 = ++v;
+    }
+
+    @Actor
+    public void actor2(IntResult2 r) {
+        r.r2 = ++v;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/ConcurrencySample_01_OperationAtomicity.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.IntResult1;
+import org.openjdk.jcstress.infra.results.IntResult2;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.openjdk.jcstress.annotations.Expect.*;
+
+public class ConcurrencySample_01_OperationAtomicity {
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        This test demonstrates the operation atomicity tests. First, the naive
+        test that tests if plain increment is indivisible or not. It is not, as
+        jcstress would tell on just about any platform.
+
+              [OK] org.openjdk.jcstress.samples.ConcurrencySample_01_OperationAtomicity.PlainIncrement
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                       1     4,090,172   ACCEPTABLE_INTERESTING  One update lost.
+                       2   200,723,108               ACCEPTABLE  Both updates.
+    */
+
+    @JCStressTest
+    @Outcome(id = "1", expect = ACCEPTABLE_INTERESTING, desc = "One update lost.")
+    @Outcome(id = "2", expect = ACCEPTABLE,  desc = "Both updates.")
+    @State
+    public static class PlainIncrement {
+        int v;
+
+        @Actor
+        public void actor1() {
+            v++;
+        }
+
+        @Actor
+        public void actor2() {
+            v++;
+        }
+
+        @Arbiter
+        public void arbiter(IntResult1 r) {
+            r.r1 = v;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+         Volatile increment is not atomic either. The mere modifier cannot resolve
+         the problem with having distinct read and write operations, that are not
+         atomic together.
+
+              [OK] org.openjdk.jcstress.samples.ConcurrencySample_01_OperationAtomicity.VolatileIncrement
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                       1        25,641   ACCEPTABLE_INTERESTING  One update lost.
+                       2   116,446,539               ACCEPTABLE  Both updates.
+     */
+
+    @JCStressTest
+    @Outcome(id = "1", expect = ACCEPTABLE_INTERESTING, desc = "One update lost.")
+    @Outcome(id = "2", expect = ACCEPTABLE, desc = "Both updates.")
+    @State
+    public static class VolatileIncrement {
+        volatile int v;
+
+        @Actor
+        public void actor1() {
+            v++;
+        }
+
+        @Actor
+        public void actor2() {
+            v++;
+        }
+
+        @Arbiter
+        public void arbiter(IntResult1 r) {
+            r.r1 = v;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        AtomicInteger.incrementAndGet() is atomic.
+
+              [OK] org.openjdk.jcstress.samples.ConcurrencySample_01_OperationAtomicity.AtomicIncrement
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                       1             0     FORBIDDEN  One update lost.
+                       2   168,640,200    ACCEPTABLE  Both updates.
+     */
+
+    @JCStressTest
+    @Outcome(id = "1", expect = FORBIDDEN,  desc = "One update lost.")
+    @Outcome(id = "2", expect = ACCEPTABLE, desc = "Both updates.")
+    @State
+    public static class AtomicIncrement {
+        AtomicInteger ai = new AtomicInteger();
+
+        @Actor
+        public void actor1() {
+            ai.incrementAndGet();
+        }
+
+        @Actor
+        public void actor2() {
+            ai.incrementAndGet();
+        }
+
+        @Arbiter
+        public void arbiter(IntResult1 r) {
+            r.r1 = ai.get();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/ConcurrencySample_02_ConcurrentHashMap.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.StringResult2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.openjdk.jcstress.annotations.Expect.*;
+
+public class ConcurrencySample_02_ConcurrentHashMap {
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        This test demonstrates the operation atomicity tests, taking
+        ConcurrentHashMap-backed Multimap as the example.
+    */
+
+    public static class Multimap {
+        Map<String, List<String>> map = new ConcurrentHashMap<>();
+
+        /*
+            Contains a nasty race on putting the list into the map.
+         */
+        void addBroken(String key, String val) {
+            List<String> list = map.get(key);
+            if (list == null) {
+                list = Collections.synchronizedList(new ArrayList<>());
+                map.put(key, list);
+            }
+            list.add(val);
+        }
+
+        /*
+            Solves the race with putIfAbsent.
+         */
+        void addCorrect(String key, String val) {
+            List<String> list = map.get(key);
+            if (list == null) {
+                list = Collections.synchronizedList(new ArrayList<>());
+                List<String> exist = map.putIfAbsent(key, list);
+                if (exist != null) {
+                    list = exist;
+                }
+            }
+            list.add(val);
+        }
+
+        /*
+            Solves the race with computeIfAbsent.
+         */
+        void addCorrect8(String key, String val) {
+            List<String> list = map.computeIfAbsent(key,
+                    k -> Collections.synchronizedList(new ArrayList<>()));
+            list.add(val);
+        }
+
+        String poll(String key, int idx) {
+            List<String> list = map.get(key);
+            return (list.size() > idx) ? list.get(idx) : null;
+        }
+    }
+
+    /*
+       ----------------------------------------------------------------------------------------------------------
+
+        Broken Multimap is broken, it contains a race.
+
+              [OK] org.openjdk.jcstress.samples.ConcurrencySample_02_ConcurrentHashMap.BrokenMultimap
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                Bar, Baz     5,635,469               ACCEPTABLE  Both updates.
+               Bar, null     1,691,183   ACCEPTABLE_INTERESTING  One update lost.
+                Baz, Bar     5,821,971               ACCEPTABLE  Both updates.
+               Baz, null     1,690,007   ACCEPTABLE_INTERESTING  One update lost.
+     */
+
+    @JCStressTest
+    @Outcome(id = { "Bar, null", "Baz, null" }, expect = ACCEPTABLE_INTERESTING, desc = "One update lost.")
+    @Outcome(id = { "Bar, Baz", "Baz, Bar"},    expect = ACCEPTABLE, desc = "Both updates.")
+    @State
+    public static class BrokenMultimap extends Multimap {
+        @Actor
+        public void actor1() {
+            addBroken("Foo", "Bar");
+        }
+
+        @Actor
+        public void actor2() {
+            addBroken("Foo", "Baz");
+        }
+
+        @Arbiter
+        public void arbiter(StringResult2 s) {
+            s.r1 = poll("Foo", 0);
+            s.r2 = poll("Foo", 1);
+        }
+    }
+
+    /*
+       ----------------------------------------------------------------------------------------------------------
+
+        putIfAbsent-style multimap does atomic updates.
+
+              [OK] org.openjdk.jcstress.samples.ConcurrencySample_02_ConcurrentHashMap.CorrectMultimap
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                Bar, Baz     6,948,547    ACCEPTABLE  Both updates.
+               Bar, null             0     FORBIDDEN  One update lost.
+                Baz, Bar     7,360,653    ACCEPTABLE  Both updates.
+               Baz, null             0     FORBIDDEN  One update lost.
+     */
+
+
+    @JCStressTest
+    @Outcome(id = { "Bar, null", "Baz, null" }, expect = FORBIDDEN, desc = "One update lost.")
+    @Outcome(id = { "Bar, Baz", "Baz, Bar"},    expect = ACCEPTABLE, desc = "Both updates.")
+    @State
+    public static class CorrectMultimap extends Multimap {
+        @Actor
+        public void actor1() {
+            addCorrect("Foo", "Bar");
+        }
+
+        @Actor
+        public void actor2() {
+            addCorrect("Foo", "Baz");
+        }
+
+        @Arbiter
+        public void arbiter(StringResult2 s) {
+            s.r1 = poll("Foo", 0);
+            s.r2 = poll("Foo", 1);
+        }
+    }
+
+
+
+
+    /*
+       ----------------------------------------------------------------------------------------------------------
+
+        computeIfAbsent-style multimap does atomic updates.
+
+              [OK] org.openjdk.jcstress.samples.ConcurrencySample_02_ConcurrentHashMap.CorrectJDK8Multimap
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                Bar, Baz     6,250,933    ACCEPTABLE  Both updates.
+               Bar, null             0     FORBIDDEN  One update lost.
+                Baz, Bar     6,412,677    ACCEPTABLE  Both updates.
+               Baz, null             0     FORBIDDEN  One update lost.
+     */
+
+    @JCStressTest
+    @Outcome(id = { "Bar, null", "Baz, null" }, expect = FORBIDDEN, desc = "One update lost.")
+    @Outcome(id = { "Bar, Baz", "Baz, Bar"},    expect = ACCEPTABLE, desc = "Both updates.")
+    @State
+    public static class CorrectJDK8Multimap extends Multimap {
+        @Actor
+        public void actor1() {
+            addCorrect8("Foo", "Bar");
+        }
+
+        @Actor
+        public void actor2() {
+            addCorrect8("Foo", "Baz");
+        }
+
+        @Arbiter
+        public void arbiter(StringResult2 s) {
+            s.r1 = poll("Foo", 0);
+            s.r2 = poll("Foo", 1);
+        }
+    }
+
+}
--- a/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_01_Simple.java	Fri Jan 20 22:07:08 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2016, Red Hat Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.jcstress.samples;
-
-import org.openjdk.jcstress.annotations.*;
-import org.openjdk.jcstress.infra.results.IntResult2;
-
-/*
-    This is our first concurrency test. It is deliberately simplistic to show
-    testing approaches, introduce JCStress APIs, etc.
-
-    Suppose we want to see if the field increment is atomic. We can make test
-    with two actors, both actors incrementing the field and recording what
-    value they observed into the result object. As JCStress runs, it will
-    invoke these methods on the objects holding the field once per each actor
-    and instance, and record what results are coming from there.
-
-    Done enough times, we will get the history of observed results, and that
-    would tell us something about the concurrent behavior. For example, running
-    this test would yield:
-
-          [OK] o.o.j.t.JCStressSample_01_Simple
-        (JVM args: [-server])
-      Observed state   Occurrences   Expectation  Interpretation
-                1, 1    54,734,140    ACCEPTABLE  Both threads came up with the same value: atomicity failure.
-                1, 2    47,037,891    ACCEPTABLE  actor1 incremented, then actor2.
-                2, 1    53,204,629    ACCEPTABLE  actor2 incremented, then actor1.
-
-     How to run this test:
-       $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_01_Simple
- */
-
-// Mark the class as JCStress test.
-@JCStressTest
-
-// These are the test outcomes.
-@Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
-@Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
-@Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
-
-// This is a state object
-@State
-public class JCStress_APISample_01_Simple {
-
-    int v;
-
-    @Actor
-    public void actor1(IntResult2 r) {
-        r.r1 = ++v; // record result from actor1 to field r1
-    }
-
-    @Actor
-    public void actor2(IntResult2 r) {
-        r.r2 = ++v; // record result from actor2 to field r2
-    }
-
-}
--- a/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_02_Arbiters.java	Fri Jan 20 22:07:08 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2016, Red Hat Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.jcstress.samples;
-
-import org.openjdk.jcstress.annotations.*;
-import org.openjdk.jcstress.infra.results.IntResult1;
-
-/*
-    Another flavor of the same test as JCStress_APISample_01_Simple is using
-    arbiters. Arbiters run after both actors, and therefore can observe the
-    final result.
-
-    This allows to directly observe the atomicity failure:
-
-          [OK] org.openjdk.jcstress.samples.JCStress_APISample_02_Arbiters
-        (JVM args: [-server])
-      Observed state   Occurrences              Expectation  Interpretation
-                   1       940,359   ACCEPTABLE_INTERESTING  One update lost: atomicity failure.
-                   2   168,950,601               ACCEPTABLE  Actors updated independently.
-
-    How to run this test:
-       $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_02_Arbiters
- */
-
-@JCStressTest
-
-// These are the test outcomes.
-@Outcome(id = "1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "One update lost: atomicity failure.")
-@Outcome(id = "2", expect = Expect.ACCEPTABLE, desc = "Actors updated independently.")
-@State
-public class JCStress_APISample_02_Arbiters {
-
-    int v;
-
-    @Actor
-    public void actor1() {
-        v++;
-    }
-
-    @Actor
-    public void actor2() {
-        v++;
-    }
-
-    @Arbiter
-    public void arbiter(IntResult1 r) {
-        r.r1 = v;
-    }
-
-}
--- a/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_03_Termination.java	Fri Jan 20 22:07:08 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2016, Red Hat Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.jcstress.samples;
-
-import org.openjdk.jcstress.annotations.*;
-
-/*
-    Some concurrency tests are not following the "run continously" pattern. One
-    of interesting test groups is that asserts if the code had terminated after
-    a signal.
-
-    Here, we use a single @Actor that busy-waits on a field, and a @Signal that
-    sets that field. JCStress would start actor, and then deliver the signal.
-    If it exits in reasonable time, it will record "TERMINATED" result, otherwise
-    record "STALE".
-
-    How to run this test:
-       $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_03_Termination
- */
-
-@JCStressTest(Mode.Termination)
-@Outcome(id = "TERMINATED", expect = Expect.ACCEPTABLE, desc = "Gracefully finished.")
-@Outcome(id = "STALE", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Test hung up.")
-@State
-public class JCStress_APISample_03_Termination {
-
-    int v;
-
-    @Actor
-    public void actor1() {
-        while (v == 0) {
-            // spin
-        }
-    }
-
-    @Signal
-    public void signal() {
-        v = 1;
-    }
-
-}
--- a/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_04_Nesting.java	Fri Jan 20 22:07:08 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2016, Red Hat Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.jcstress.samples;
-
-import org.openjdk.jcstress.annotations.*;
-import org.openjdk.jcstress.infra.results.IntResult2;
-
-/*
-    It is sometimes convenient to put the tests in the same source file for
-    better comparison. JCStress allows to nest tests like this:
-
-    How to run this test:
-       $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_04_Nesting
- */
-
-public class JCStress_APISample_04_Nesting {
-
-    @JCStressTest
-    @Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
-    @Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
-    @Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
-    @State
-    public static class PlainTest {
-        int v;
-
-        @Actor
-        public void actor1(IntResult2 r) {
-            r.r1 = ++v;
-        }
-
-        @Actor
-        public void actor2(IntResult2 r) {
-            r.r2 = ++v;
-        }
-    }
-
-    @JCStressTest
-    @Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
-    @Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
-    @Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
-    @State
-    public static class VolatileTest {
-        volatile int v;
-
-        @Actor
-        public void actor1(IntResult2 r) {
-            r.r1 = ++v;
-        }
-
-        @Actor
-        public void actor2(IntResult2 r) {
-            r.r2 = ++v;
-        }
-    }
-
-}
--- a/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_05_SharedMetadata.java	Fri Jan 20 22:07:08 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2016, Red Hat Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.jcstress.samples;
-
-import org.openjdk.jcstress.annotations.*;
-import org.openjdk.jcstress.infra.results.IntResult2;
-
-/*
-   In many cases, tests share the outcomes and other metadata. To common them,
-   there is a special @JCStressMeta annotation that says to look up the metadata
-   at another class.
-
-   How to run this test:
-      $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_05_SharedMetadata
- */
-
-@Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
-@Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
-@Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
-public class JCStress_APISample_05_SharedMetadata {
-
-    @JCStressTest
-    @JCStressMeta(JCStress_APISample_05_SharedMetadata.class)
-    @State
-    public static class PlainTest {
-        int v;
-
-        @Actor
-        public void actor1(IntResult2 r) {
-            r.r1 = ++v;
-        }
-
-        @Actor
-        public void actor2(IntResult2 r) {
-            r.r2 = ++v;
-        }
-    }
-
-    @JCStressTest
-    @JCStressMeta(JCStress_APISample_05_SharedMetadata.class)
-    @State
-    public static class VolatileTest {
-        volatile int v;
-
-        @Actor
-        public void actor1(IntResult2 r) {
-            r.r1 = ++v;
-        }
-
-        @Actor
-        public void actor2(IntResult2 r) {
-            r.r2 = ++v;
-        }
-    }
-
-}
--- a/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JCStress_APISample_06_Descriptions.java	Fri Jan 20 22:07:08 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2016, Red Hat Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.jcstress.samples;
-
-import org.openjdk.jcstress.annotations.*;
-import org.openjdk.jcstress.infra.results.IntResult2;
-
-/*
-    JCStress also allows to put the descriptions and references right at the test.
-    This helps to identify the goal for the test, as well as the discussions about
-    the behavior in question.
-
-   How to run this test:
-      $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_06_Descriptions
- */
-
-@JCStressTest
-
-// Optional test description
-@Description("Sample Hello World test")
-
-// Optional references. @Ref is repeatable.
-@Ref("http://openjdk.java.net/projects/code-tools/jcstress/")
-
-@Outcome(id = "1, 1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Both actors came up with the same value: atomicity failure.")
-@Outcome(id = "1, 2", expect = Expect.ACCEPTABLE, desc = "actor1 incremented, then actor2.")
-@Outcome(id = "2, 1", expect = Expect.ACCEPTABLE, desc = "actor2 incremented, then actor1.")
-@State
-public class JCStress_APISample_06_Descriptions {
-
-    int v;
-
-    @Actor
-    public void actor1(IntResult2 r) {
-        r.r1 = ++v;
-    }
-
-    @Actor
-    public void actor2(IntResult2 r) {
-        r.r2 = ++v;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_01_AccessAtomicity.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.IntResult1;
+import org.openjdk.jcstress.infra.results.LongResult1;
+import org.openjdk.jcstress.util.UnsafeHolder;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteBuffer;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class JMMSample_01_AccessAtomicity {
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        This is our first case: access atomicity. Most basic types come with an
+        intuitive property: the reads and the writes of these basic types happen
+        in full, even under races:
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_01_AccessAtomicity.Integers
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                      -1   221,268,498    ACCEPTABLE  Seeing the full value.
+                       0    17,764,332    ACCEPTABLE  Seeing the default value: writer had not acted yet.
+
+    */
+
+    @JCStressTest
+    @Outcome(id = "0",  expect = Expect.ACCEPTABLE, desc = "Seeing the default value: writer had not acted yet.")
+    @Outcome(id = "-1", expect = Expect.ACCEPTABLE, desc = "Seeing the full value.")
+    @Outcome(expect = Expect.FORBIDDEN, desc = "Other cases are forbidden.")
+    @State
+    public static class Integers {
+        int v;
+
+        @Actor
+        public void writer() {
+            v = 0xFFFFFFFF;
+        }
+
+        @Actor
+        public void reader(IntResult1 r) {
+            r.r1 = v;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        There are a few interesting exceptions codified in Java Language Specification,
+        under 17.7 "Non-Atomic Treatment of double and long". It says that longs and
+        doubles could be treated non-atomically.
+
+        NOTE: This test would yield interesting results on 32-bit VMs.
+
+               [OK] org.openjdk.jcstress.samples.JMMSample_01_AccessAtomicity.Longs
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                      -1   181,716,629               ACCEPTABLE  Seeing the full value.
+             -4294967296        40,481   ACCEPTABLE_INTERESTING  Other cases are violating access atomicity, but allowed u...
+                       0    10,439,305               ACCEPTABLE  Seeing the default value: writer had not acted yet.
+              4294967295         2,545   ACCEPTABLE_INTERESTING  Other cases are violating access atomicity, but allowed u...
+     */
+
+    @JCStressTest
+    @Outcome(id = "0",  expect = Expect.ACCEPTABLE, desc = "Seeing the default value: writer had not acted yet.")
+    @Outcome(id = "-1", expect = Expect.ACCEPTABLE, desc = "Seeing the full value.")
+    @Outcome(expect = Expect.ACCEPTABLE_INTERESTING, desc = "Other cases are violating access atomicity, but allowed under JLS.")
+    @Ref("https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7")
+    @State
+    public static class Longs {
+        long v;
+
+        @Actor
+        public void writer() {
+            v = 0xFFFFFFFF_FFFFFFFFL;
+        }
+
+        @Actor
+        public void reader(LongResult1 r) {
+            r.r1 = v;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Recovering the access atomicity is possible with making the field "volatile":
+
+               [OK] org.openjdk.jcstress.samples.JMMSample_01_AccessAtomicity.VolatileLongs
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                      -1    25,920,268    ACCEPTABLE  Seeing the full value.
+                       0   101,853,902    ACCEPTABLE  Seeing the default value: writer had not acted yet.
+     */
+
+    @JCStressTest
+    @Outcome(id = "0",  expect = Expect.ACCEPTABLE, desc = "Seeing the default value: writer had not acted yet.")
+    @Outcome(id = "-1", expect = Expect.ACCEPTABLE, desc = "Seeing the full value.")
+    @Outcome(expect = Expect.FORBIDDEN, desc = "Other cases are forbidden.")
+    @State
+    public static class VolatileLongs {
+        volatile long v;
+
+        @Actor
+        public void writer() {
+            v = 0xFFFFFFFF_FFFFFFFFL;
+        }
+
+        @Actor
+        public void reader(LongResult1 r) {
+            r.r1 = v;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Since Java 9, VarHandles in "opaque" access mode also require access atomicity.
+        (The same applies for "acquire/release", and "volatile" access modes too!)
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_01_AccessAtomicity.OpaqueLongs
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                      -1   161,358,765    ACCEPTABLE  Seeing the full value.
+                       0     5,778,795    ACCEPTABLE  Seeing the default value: writer had not acted yet.
+     */
+
+    @JCStressTest
+    @Outcome(id = "0",  expect = Expect.ACCEPTABLE, desc = "Seeing the default value: writer had not acted yet.")
+    @Outcome(id = "-1", expect = Expect.ACCEPTABLE, desc = "Seeing the full value.")
+    @Outcome(expect = Expect.FORBIDDEN, desc = "Other cases are forbidden.")
+    @State
+    public static class OpaqueLongs {
+
+        static final VarHandle VH;
+
+        static {
+            try {
+                VH = MethodHandles.lookup().findVarHandle(OpaqueLongs.class, "v", long.class);
+            } catch (NoSuchFieldException | IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        long v;
+
+        @Actor
+        public void writer() {
+            VH.setOpaque(this, 0xFFFFFFFF_FFFFFFFFL);
+        }
+
+        @Actor
+        public void reader(LongResult1 r) {
+            r.r1 = (long) VH.getOpaque(this);
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        While the spec requirements for field and array element accesses are
+        strict, the implementations of concrete classes may have a relaxed
+        semantics. Take ByteBuffer where we can read the 4-byte integer from
+        an arbitrary offset.
+
+        Older ByteBuffer implementations accessed one byte at a time, and that
+        required merging/splitting anything larger than a byte into the individual
+        operations. Of course, there is no access atomicity there by construction.
+        In newer ByteBuffer implementations, the _aligned_ accesses are done with
+        larger instructions that gives back atomicity. Misaligned accesses would
+        still have to do several narrower accesses on machines that don't support
+        misalignments.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_01_AccessAtomicity.ByteBuffers
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                      -1    32,580,349               ACCEPTABLE  Seeing the full value.
+               -16777216         2,791   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                    -256         2,739   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                  -65536         2,848   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                       0     5,961,926               ACCEPTABLE  Seeing the default value: writer had not acted yet.
+                16777215         1,467   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                     255         1,502   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                   65535         1,498   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+    */
+
+    @JCStressTest
+    @Outcome(id = "0",  expect = Expect.ACCEPTABLE, desc = "Seeing the default value: writer had not acted yet.")
+    @Outcome(id = "-1", expect = Expect.ACCEPTABLE, desc = "Seeing the full value.")
+    @Outcome(expect = Expect.ACCEPTABLE_INTERESTING, desc = "Other cases are allowed, because reads/writes are not atomic.")
+    @State
+    public static class ByteBuffers {
+        public static final int SIZE = 256;
+
+        ByteBuffer bb = ByteBuffer.allocate(SIZE);
+        int idx = ThreadLocalRandom.current().nextInt(SIZE - 4);
+
+        @Actor
+        public void writer() {
+            bb.putInt(idx, 0xFFFFFFFF);
+        }
+
+        @Actor
+        public void reader(IntResult1 r) {
+            r.r1 = bb.getInt(idx);
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        However, even if the misaligned accesses is supported by hardware, it would never
+        be guaranteed atomic. For example, reading the value that spans two cache-lines would
+        not be atomic, even if we manage to issue a single instruction for access.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_01_AccessAtomicity.UnsafeCrossCacheLine
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                      -1    40,495,875               ACCEPTABLE  Seeing the full value.
+               -16777216           760   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                    -256           726   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                  -65536           789   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                       0     2,136,183               ACCEPTABLE  Seeing the default value: writer had not acted yet.
+                16777215           539   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                     255           554   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+                   65535           574   ACCEPTABLE_INTERESTING  Other cases are allowed, because reads/writes are not ato...
+     */
+
+    @JCStressTest
+    @Outcome(id = "0",  expect = Expect.ACCEPTABLE, desc = "Seeing the default value: writer had not acted yet.")
+    @Outcome(id = "-1", expect = Expect.ACCEPTABLE, desc = "Seeing the full value.")
+    @Outcome(expect = Expect.ACCEPTABLE_INTERESTING, desc = "Other cases are allowed, because reads/writes are not atomic.")
+    @State
+    public static class UnsafeCrossCacheLine {
+
+        public static final int SIZE = 256;
+        public static final long ARRAY_BASE_OFFSET = UnsafeHolder.U.arrayBaseOffset(byte[].class);
+        public static final long ARRAY_BASE_SCALE = UnsafeHolder.U.arrayIndexScale(byte[].class);
+
+        byte[] ss = new byte[SIZE];
+        long off = ARRAY_BASE_OFFSET + ARRAY_BASE_SCALE * ThreadLocalRandom.current().nextInt(SIZE - 4);
+
+        @Actor
+        public void writer() {
+            UnsafeHolder.U.putInt(ss, off, 0xFFFFFFFF);
+        }
+
+        @Actor
+        public void reader(IntResult1 r) {
+            r.r1 = UnsafeHolder.U.getInt(ss, off);
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Conclusion: for fields and array elements access atomicity is guaranteed, except
+        for non-volatile longs and doubles. Regaining the atomicity is possible with anything
+        stronger than a plain read/write.
+
+        Are reads/writes atomic?
+
+                        boolean,    byte,   char,   short,     int,    float,  double,  long,   Object
+
+          plain:            yes      yes     yes      yes      yes       yes       NO     NO      yes
+          volatile:         yes      yes     yes      yes      yes       yes      YES    YES      yes
+
+          VH (plain):       yes      yes     yes      yes      yes       yes       NO     NO      yes
+          VH (opaque):      yes      yes     yes      yes      yes       yes      YES    YES      yes
+          VH (acq/rel):     yes      yes     yes      yes      yes       yes      YES    YES      yes
+          VH (volatile):    yes      yes     yes      yes      yes       yes      YES    YES      yes
+
+        Access atomicity for unnatural accesses is not guaranteed. Alignment issues,
+        implementation quirks, etc. may deconstruct the access atomicity. The case of single
+        aligned reads/writes is similar to the usual language guarantees.
+
+        Are reads/writes atomic?
+
+                                                   access type:
+                                    multiple,   single misaligned,  single aligned
+
+          plain:                           no                  no,          YES/NO (yes, except for long/double)
+          volatile:                        no                  no,             YES
+          VH (plain):                      no,                 no,          YES/NO (yes, except for long/double)
+          VH (opaque):                     no,                 no,             YES
+          VH (acq/rel):                    no,                 no,             YES
+          VH (volatile):                   no,                 no,             YES
+
+     */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_02_WordTearing.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.BooleanResult2;
+
+import java.util.BitSet;
+
+public class JMMSample_02_WordTearing {
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Java Memory Model prohibits word tearing. That is, it mandates treating
+        every field and array element as distinct, and the operations for one
+        element should not disturb others.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_02_WordTearing.JavaArrays
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+              true, true   228,447,200    ACCEPTABLE  Seeing both updates intact.
+    */
+
+    @JCStressTest
+    @Outcome(id = "true, true", expect = Expect.ACCEPTABLE, desc = "Seeing both updates intact.")
+    @Outcome(expect = Expect.FORBIDDEN, desc = "Other cases are forbidden.")
+    @State
+    public static class JavaArrays {
+        boolean[] bs = new boolean[2];
+
+        @Actor
+        public void writer1() {
+            bs[0] = true;
+        }
+
+        @Actor
+        public void writer2() {
+            bs[1] = true;
+        }
+
+        @Arbiter
+        public void arbiter(BooleanResult2 r) {
+            r.r1 = bs[0];
+            r.r2 = bs[1];
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        However, while that requirement is enforced for fields and array elements, the
+        implementations may still violate this requirement, if, say, they pack elements
+        densely, and read/write adjacent elements routinely.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_02_WordTearing.BitSets
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+             false, true     1,107,454   ACCEPTABLE_INTERESTING  Destroyed one update.
+             true, false     1,297,199   ACCEPTABLE_INTERESTING  Destroyed one update.
+              true, true   147,209,607               ACCEPTABLE  Seeing both updates intact.
+     */
+
+    @JCStressTest
+    @Outcome(id = "true, true",  expect = Expect.ACCEPTABLE, desc = "Seeing both updates intact.")
+    @Outcome(id = "false, true", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Destroyed one update.")
+    @Outcome(id = "true, false", expect = Expect.ACCEPTABLE_INTERESTING, desc = "Destroyed one update.")
+    @State
+    public static class BitSets {
+
+        BitSet bs = new BitSet();
+
+        @Actor
+        public void writer1() {
+            bs.set(0);
+        }
+
+        @Actor
+        public void writer2() {
+            bs.set(1);
+        }
+
+        @Arbiter
+        public void arbiter(BooleanResult2 r) {
+            r.r1 = bs.get(0);
+            r.r2 = bs.get(1);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_03_Coherence.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.*;
+import org.openjdk.jcstress.infra.results.IntResult2;
+
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE;
+import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING;
+import static org.openjdk.jcstress.annotations.Expect.FORBIDDEN;
+
+public class JMMSample_03_Coherence {
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Yet another subtle and intuitive property comes from the naive understanding
+        of how programs work. Under Java Memory Model, in absence of synchronization,
+        the order of independent reads is undefined. That includes reads of the *same*
+        variable!
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_03_Coherence.SameRead
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                    0, 0     4,593,916               ACCEPTABLE  Doing both reads early.
+                    0, 1         2,507               ACCEPTABLE  Doing first read early, not surprising.
+                    1, 0        48,132   ACCEPTABLE_INTERESTING  First read seen racy value early, and the second one did ...
+                    1, 1    88,146,175               ACCEPTABLE  Doing both reads late.
+    */
+
+    @JCStressTest
+    @Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
+    @Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
+    @Outcome(id = "0, 1", expect = ACCEPTABLE, desc = "Doing first read early, not surprising.")
+    @Outcome(id = "1, 0", expect = ACCEPTABLE_INTERESTING, desc = "First read seen racy value early, and the second one did not.")
+    @State
+    public static class SameRead {
+
+        private final Holder h1 = new Holder();
+        private final Holder h2 = h1;
+
+        private static class Holder {
+            int a;
+            int trap;
+        }
+
+        @Actor
+        public void actor1() {
+            h1.a = 1;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            Holder h1 = this.h1;
+            Holder h2 = this.h2;
+
+            // Spam null-pointer check folding: try to step on NPEs early.
+            // Doing this early frees compiler from moving h1.a and h2.a loads
+            // around, because it would not have to maintain exception order anymore.
+            h1.trap = 0;
+            h2.trap = 0;
+
+            // Spam alias analysis: the code effectively reads the same field twice,
+            // but compiler does not know (h1 == h2) (i.e. does not check it, as
+            // this is not a profitable opt for real code), so it issues two independent
+            // loads.
+            r.r1 = h1.a;
+            r.r2 = h2.a;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        The stronger property -- coherence -- mandates that the writes to the same
+        variable to be observed in a total order (that implies that _observers_ are
+        also ordered). Java "volatile" assumes this property.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_03_Coherence.SameVolatileRead
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                    0, 0    66,401,704    ACCEPTABLE  Doing both reads early.
+                    0, 1       102,587    ACCEPTABLE  Doing first read early, not surprising.
+                    1, 0             0     FORBIDDEN  Violates coherence.
+                    1, 1    15,507,759    ACCEPTABLE  Doing both reads late.
+     */
+
+    @JCStressTest
+    @Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
+    @Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
+    @Outcome(id = "0, 1", expect = ACCEPTABLE, desc = "Doing first read early, not surprising.")
+    @Outcome(id = "1, 0", expect = FORBIDDEN, desc = "Violates coherence.")
+    @State
+    public static class SameVolatileRead {
+
+        private final Holder h1 = new Holder();
+        private final Holder h2 = h1;
+
+        private static class Holder {
+            volatile int a;
+            int trap;
+        }
+
+        @Actor
+        public void actor1() {
+            h1.a = 1;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            Holder h1 = this.h1;
+            Holder h2 = this.h2;
+
+            h1.trap = 0;
+            h2.trap = 0;
+
+            r.r1 = h1.a;
+            r.r2 = h2.a;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        VarHandles "opaque" mode also provide coherency.
+
+               [OK] org.openjdk.jcstress.samples.JMMSample_03_Coherence.SameOpaqueRead
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                    0, 0     5,857,995    ACCEPTABLE  Doing both reads early.
+                    0, 1        55,082    ACCEPTABLE  Doing first read early, not surprising.
+                    1, 0             0     FORBIDDEN  Violates coherence.
+                    1, 1   114,114,673    ACCEPTABLE  Doing both reads late.
+     */
+
+    @JCStressTest
+    @Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
+    @Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
+    @Outcome(id = "0, 1", expect = ACCEPTABLE, desc = "Doing first read early, not surprising.")
+    @Outcome(id = "1, 0", expect = FORBIDDEN, desc = "Violates coherence.")
+    @State
+    public static class SameOpaqueRead {
+
+        static final VarHandle VH;
+
+        static {
+            try {
+                VH = MethodHandles.lookup().findVarHandle(Holder.class, "a", int.class);
+            } catch (NoSuchFieldException | IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        private final Holder h1 = new Holder();
+        private final Holder h2 = h1;
+
+        private static class Holder {
+            int a;
+            int trap;
+        }
+
+        @Actor
+        public void actor1() {
+            VH.setOpaque(h1, 1);
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            Holder h1 = this.h1;
+            Holder h2 = this.h2;
+
+            h1.trap = 0;
+            h2.trap = 0;
+
+            r.r1 = (int) VH.getOpaque(h1);
+            r.r2 = (int) VH.getOpaque(h2);
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Conclusion: coherency is something that is assumed intuitively. However, under the
+        data race (= in the absence of synchronization) the absence of coherence for plain
+        accesses may lead to surprising results.
+
+        Are reads/writes coherent?
+
+          plain:                           no
+          volatile:                       YES
+          VH (plain):                      no
+          VH (opaque):                    YES
+          VH (acq/rel):                   YES
+          VH (volatile):                  YES
+     */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_04_PartialOrder.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.Actor;
+import org.openjdk.jcstress.annotations.JCStressTest;
+import org.openjdk.jcstress.annotations.Outcome;
+import org.openjdk.jcstress.annotations.State;
+import org.openjdk.jcstress.infra.results.IntResult2;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+import static org.openjdk.jcstress.annotations.Expect.*;
+
+public class JMMSample_04_PartialOrder {
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        The next property comes in relation to inter-thread semantics. In JMM,
+        happens-before mandates what results are plausible and what are not, when
+        non-synchronized reads are involved. That order is partial, so there are
+        pairs of reads/writes we can tell nothing about order-wise.
+
+        For example, in the case of two non-volatile variables, JMM allows observing
+        "1, 0"!
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_04_PartialOrder.PlainReads
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                    0, 0     3,579,845               ACCEPTABLE  Doing both reads early.
+                    0, 1        31,148               ACCEPTABLE  Caught in the middle: $x is visible, $y is not.
+                    1, 0        23,841   ACCEPTABLE_INTERESTING  Seeing $y, but not $x!
+                    1, 1   114,662,576               ACCEPTABLE  Doing both reads late.
+    */
+
+    @JCStressTest
+    @Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
+    @Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
+    @Outcome(id = "0, 1", expect = ACCEPTABLE, desc = "Caught in the middle: $x is visible, $y is not.")
+    @Outcome(id = "1, 0", expect = ACCEPTABLE_INTERESTING, desc = "Seeing $y, but not $x!")
+    @State
+    public static class PlainReads {
+        int x;
+        int y;
+
+        @Actor
+        public void actor1() {
+            x = 1;
+            y = 1;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            r.r1 = y;
+            r.r2 = x;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        The easiest way to solve this is to turn $v into volatile variable. In JMM,
+        that would mean that the only execution which can justify (1, 0) is invalid:
+        it has broken happens-before consistency. E.g. in the execution
+
+          write(x, 1) --hb--> write(y, 1) --hb--> read(y):1 --hb--> read(x):1
+
+        ...read(x) should have seen "1", not "0".
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_04_PartialOrder.VolatileGuard
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                    0, 0    99,074,452    ACCEPTABLE  Doing both reads early.
+                    0, 1     2,309,155    ACCEPTABLE  Caught in the middle: $x is visible, $y is not.
+                    1, 0             0     FORBIDDEN  Seeing $y, but not $x!
+                    1, 1    43,441,703    ACCEPTABLE  Doing both reads late.
+     */
+
+    @JCStressTest
+    @Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
+    @Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
+    @Outcome(id = "0, 1", expect = ACCEPTABLE, desc = "Caught in the middle: $x is visible, $y is not.")
+    @Outcome(id = "1, 0", expect = FORBIDDEN, desc = "Seeing $y, but not $x!")
+    @State
+    public static class VolatileGuard {
+
+        int x;
+        volatile int y;
+
+        @Actor
+        public void actor1() {
+            x = 1;
+            y = 1;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            r.r1 = y;
+            r.r2 = x;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        VarHandles acquire and release modes can be used to achieve the same effect, but
+        anything weaker is not guaranteed to work.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_04_PartialOrder.AcquireReleaseGuard
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                    0, 0     4,724,357    ACCEPTABLE  Doing both reads early.
+                    0, 1       292,421    ACCEPTABLE  Caught in the middle: $x is visible, $y is not.
+                    1, 0             0     FORBIDDEN  Seeing $y, but not $x!
+                    1, 1   144,332,652    ACCEPTABLE  Doing both reads late.
+     */
+
+    @JCStressTest
+    @Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
+    @Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
+    @Outcome(id = "0, 1", expect = ACCEPTABLE, desc = "Caught in the middle: $x is visible, $y is not.")
+    @Outcome(id = "1, 0", expect = FORBIDDEN, desc = "Seeing $y, but not $x!")
+    @State
+    public static class AcquireReleaseGuard {
+        static final VarHandle VH;
+
+        static {
+            try {
+                VH = MethodHandles.lookup().findVarHandle(AcquireReleaseGuard.class, "y", int.class);
+            } catch (NoSuchFieldException | IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        int x;
+        int y;
+
+        @Actor
+        public void actor1() {
+            x = 1;
+            VH.setRelease(this, 1);
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            r.r1 = (int) VH.getAcquire(this);
+            r.r2 = x;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Of course, the same thing is achievable with locks.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_04_PartialOrder.LockGuard
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                    0, 0    29,017,795    ACCEPTABLE  Doing both reads early.
+                    0, 1             0    ACCEPTABLE  Caught in the middle: $x is visible, $y is not.
+                    1, 0             0     FORBIDDEN  Seeing $y, but not $x!
+                    1, 1    31,223,995    ACCEPTABLE  Doing both reads late.
+
+     */
+    @JCStressTest
+    @Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
+    @Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
+    @Outcome(id = "0, 1", expect = ACCEPTABLE, desc = "Caught in the middle: $x is visible, $y is not.")
+    @Outcome(id = "1, 0", expect = FORBIDDEN, desc = "Seeing $y, but not $x!")
+    @State
+    public static class LockGuard {
+
+        int x;
+        int y;
+
+        @Actor
+        public void actor1() {
+            synchronized (this) {
+                x = 1;
+                y = 1;
+            }
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            synchronized (this) {
+                r.r1 = y;
+                r.r2 = x;
+            }
+        }
+    }
+
+    /*
+       ----------------------------------------------------------------------------------------------------------
+
+        Conclusion: the minimal inter-thread semantics (happens-before) is guaranteed for acquire/releases and
+        volatiles. Anything weaker does not guarantee this effect
+
+        Do inter-thread reads/writes form partial order?
+
+          plain:                           no
+          volatile:                       yes
+          VH (plain):                      no
+          VH (opaque):                     no
+          VH (acq/rel):                   yes
+          VH (volatile):                  yes
+     */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_05_TotalOrder.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.Actor;
+import org.openjdk.jcstress.annotations.JCStressTest;
+import org.openjdk.jcstress.annotations.Outcome;
+import org.openjdk.jcstress.annotations.State;
+import org.openjdk.jcstress.infra.results.IntResult2;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+import static org.openjdk.jcstress.annotations.Expect.*;
+
+public class JMMSample_05_TotalOrder {
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Another property comes for the inter-thread semantics deals not with
+        partial, but total order. In JMM, synchronization order mandates that
+        special "synchronization" actions always form a total order, consistent
+        with program order.
+
+        The most famous example that needs total order of operation is Dekker
+        idiom, the building block of Dekker lock.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_05_TotalOrder.PlainDekker
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                    0, 0    12,006,499   ACCEPTABLE_INTERESTING  Violates sequential consistency
+                    0, 1    53,849,842               ACCEPTABLE  Trivial under sequential consistency
+                    1, 0    39,405,818               ACCEPTABLE  Trivial under sequential consistency
+                    1, 1            21               ACCEPTABLE  Trivial under sequential consistency
+    */
+
+    @JCStressTest
+    @Outcome(id = {"0, 1", "1, 0", "1, 1"}, expect = ACCEPTABLE, desc = "Trivial under sequential consistency")
+    @Outcome(id = "0, 0",                   expect = ACCEPTABLE_INTERESTING,  desc = "Violates sequential consistency")
+    @State
+    public static class PlainDekker {
+        int x;
+        int y;
+
+        @Actor
+        public void actor1(IntResult2 r) {
+            x = 1;
+            r.r1 = y;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            y = 1;
+            r.r2 = x;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Adding volatile to both $x and $y bring them together into synchronization order,
+        and thus require the results to be consistent with the case when reads/writes
+        form a total order.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_05_TotalOrder.VolatileDekker
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                    0, 0             0     FORBIDDEN  Violates sequential consistency
+                    0, 1    52,228,833    ACCEPTABLE  Trivial under sequential consistency
+                    1, 0    60,725,076    ACCEPTABLE  Trivial under sequential consistency
+                    1, 1       313,541    ACCEPTABLE  Trivial under sequential consistency
+     */
+
+    @JCStressTest
+    @Outcome(id = {"0, 1", "1, 0", "1, 1"}, expect = ACCEPTABLE, desc = "Trivial under sequential consistency")
+    @Outcome(id = "0, 0",                   expect = FORBIDDEN,  desc = "Violates sequential consistency")
+    @State
+    public static class VolatileDekker {
+        volatile int x;
+        volatile int y;
+
+        @Actor
+        public void actor1(IntResult2 r) {
+            x = 1;
+            r.r1 = y;
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            y = 1;
+            r.r2 = x;
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        VarHandles acquire and release modes are too weak to achieve the required effect.
+        VarHandles opaque mode is also too weak.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_05_TotalOrder.AcqRelDekker
+            (JVM args: [-server])
+          Observed state   Occurrences              Expectation  Interpretation
+                    0, 0    13,708,261   ACCEPTABLE_INTERESTING  Violates sequential consistency
+                    0, 1    36,033,448               ACCEPTABLE  Trivial under sequential consistency
+                    1, 0    27,158,587               ACCEPTABLE  Trivial under sequential consistency
+                    1, 1        70,204               ACCEPTABLE  Trivial under sequential consistency
+     */
+
+    @JCStressTest
+    @Outcome(id = {"0, 1", "1, 0", "1, 1"}, expect = ACCEPTABLE, desc = "Trivial under sequential consistency")
+    @Outcome(id = "0, 0",                   expect = ACCEPTABLE_INTERESTING,  desc = "Violates sequential consistency")
+    @State
+    public static class AcqRelDekker {
+        static final VarHandle VH_X;
+        static final VarHandle VH_Y;
+
+        static {
+            try {
+                VH_X = MethodHandles.lookup().findVarHandle(AcqRelDekker.class, "x", int.class);
+                VH_Y = MethodHandles.lookup().findVarHandle(AcqRelDekker.class, "y", int.class);
+            } catch (NoSuchFieldException | IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        int x;
+        int y;
+
+        @Actor
+        public void actor1(IntResult2 r) {
+            VH_X.setRelease(this, 1);
+            r.r1 = (int) VH_Y.getAcquire(this);
+        }
+
+        @Actor
+        public void actor2(IntResult2 r) {
+            VH_Y.setRelease(this, 1);
+            r.r2 = (int) VH_X.getAcquire(this);
+        }
+    }
+
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Conclusion: total order is only available for volatiles. Anything else is weaker and does not
+        give totality.
+
+        Do inter-thread reads/writes form total order consistent with program order?
+
+          plain:                           no
+          volatile:                       yes
+          VH (plain):                      no
+          VH (opaque):                     no
+          VH (acq/rel):                    no
+          VH (volatile):                  yes
+     */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/JMMSample_06_Finals.java	Sat Jan 21 14:04:07 2017 +0100
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.samples;
+
+import org.openjdk.jcstress.annotations.Actor;
+import org.openjdk.jcstress.annotations.JCStressTest;
+import org.openjdk.jcstress.annotations.Outcome;
+import org.openjdk.jcstress.annotations.State;
+import org.openjdk.jcstress.infra.results.IntResult1;
+import org.openjdk.jcstress.infra.results.IntResult2;
+import org.openjdk.jcstress.infra.results.IntResult4;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+import static org.openjdk.jcstress.annotations.Expect.*;
+
+public class JMMSample_06_Finals {
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Finals are another aspect of Java Memory Model. They allow surviving the publication
+        via the race. In other words, they provide some basic inter-thread semantics, even in
+        the absence of proper synchronization.
+
+              [OK] org.openjdk.jcstress.samples.JMMSample_06_Finals.PlainInit
+            (JVM args: [-server, -XX:+UnlockDiagnosticVMOptions, -XX:+StressLCM, -XX:+StressGCM])
+          Observed state   Occurrences              Expectation  Interpretation
+                      -1    82,909,900               ACCEPTABLE  Object is not seen yet.
+                       0             0   ACCEPTABLE_INTERESTING  Seeing partially constructed object.
+                       1             0   ACCEPTABLE_INTERESTING  Seeing partially constructed object.
+                       2             0   ACCEPTABLE_INTERESTING  Seeing partially constructed object.
+                       3             0   ACCEPTABLE_INTERESTING  Seeing partially constructed object.
+                       4             0   ACCEPTABLE_INTERESTING  Seeing partially constructed object.
+                       5           622   ACCEPTABLE_INTERESTING  Seeing partially constructed object.
+                       6         1,434   ACCEPTABLE_INTERESTING  Seeing partially constructed object.
+                       7           420   ACCEPTABLE_INTERESTING  Seeing partially constructed object.
+                       8    16,973,344               ACCEPTABLE  Seen the complete object.
+    */
+
+    @JCStressTest
+    @Outcome(id = "-1", expect = ACCEPTABLE, desc = "Object is not seen yet.")
+    @Outcome(id = {"0", "1", "2", "3", "4", "5", "6", "7"}, expect = ACCEPTABLE_INTERESTING, desc = "Seeing partially constructed object.")
+    @Outcome(id = "8", expect = ACCEPTABLE,  desc = "Seen the complete object.")
+    @State
+    public static class PlainInit {
+        int v = 1;
+
+        MyObject o;
+
+        @Actor
+        public void actor1() {
+            o = new MyObject(v);
+        }
+
+        @Actor
+        public void actor2(IntResult1 r) {
+            MyObject o = this.o;
+            if (o != null) {
+                r.r1 = o.x8 + o.x7 + o.x6 + o.x5 + o.x4 + o.x3 + o.x2 + o.x1;
+            } else {
+                r.r1 = -1;
+            }
+        }
+
+        public static class MyObject {
+            int x1, x2, x3, x4;
+            int x5, x6, x7, x8;
+            public MyObject(int v) {
+                x1 = v;
+                x2 = v;
+                x3 = v;
+                x4 = v;
+                x5 = v;
+                x6 = v;
+                x7 = v;
+                x8 = v;
+            }
+        }
+    }
+
+    /*
+      ----------------------------------------------------------------------------------------------------------
+
+        Putting finals on the fields is enough to get some safety back.
+
+               [OK] org.openjdk.jcstress.samples.JMMSample_06_Finals.FinalInit
+            (JVM args: [-server])
+          Observed state   Occurrences   Expectation  Interpretation
+                      -1   112,755,834    ACCEPTABLE  Object is not seen yet.
+                       8     3,766,026    ACCEPTABLE  Seen the complete object.
+     */
+
+    @JCStressTest
+    @Outcome(id = "-1", expect = ACCEPTABLE, desc = "Object is not seen yet.")
+    @Outcome(id = "8", expect = ACCEPTABLE,  desc = "Seen the complete object.")
+    @Outcome(expect = FORBIDDEN, desc = "Seeing partially constructed object.")
+    @State
+    public static class FinalInit {
+        int v = 1;
+
+        MyObject o;
+
+        @Actor
+        public void actor1() {
+            o = new MyObject(v);
+        }
+
+        @Actor
+        public void actor2(IntResult1 r) {
+            MyObject o = this.o;
+            if (o != null) {
+                r.r1 = o.x8 + o.x7 + o.x6 + o.x5 + o.x4 + o.x3 + o.x2 + o.x1;
+            } else {
+                r.r1 = -1;
+            }
+        }
+
+        public static class MyObject {
+            final int x1, x2, x3, x4;
+            final int x5, x6, x7, x8;
+            public MyObject(int v) {
+                x1 = v;
+                x2 = v;
+                x3 = v;
+                x4 = v;
+                x5 = v;
+                x6 = v;
+                x7 = v;
+                x8 = v;
+            }
+        }
+    }
+
+}