1

As I know, JMM does not follow Sequential Consistency, and we need the volatile keyword to guarantee visibility. A typical example without SC often describe like

A = 0;
B = 0;

--thread 1--
A = 1;
B = 1;

--thread 2--
if(B == 1){
  //at here, A is not guarantee equal to 1, A == 0 is also possible
}

Which is easy to understand. But when I want to reproduce this simple example in real Java code, I failed.

Below is the code I hope to reproduce the above concept example, I do not use the volatile here, but this code still never reach the case when a==0 and b==1.

import java.util.LinkedList;

public class test2 {
    static int a = 0;
    static int b = 0;

    static class Multithreading1 extends Thread {
        public void run() {
            try {
                sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            a = 1;
            b = 1;
        }
    }

    static class Multithreading2 extends Thread {
        public void run() {
            while (b == 0) {
                Thread.onSpinWait();
            }
            if (a == 0) {
                //never reach
                System.out.print(a);
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 1000; i++) {
            a = 0;
            b = 0;
            Multithreading1 t1 = new Multithreading1();
            t1.start();
            LinkedList<Multithreading2> t2 = new LinkedList();
            int thread_number = 16;
            for (int j = 0; j < thread_number; j++) {
                t2.add(new Multithreading2());
            }
            for (int j = 0; j < thread_number; j++) {
                t2.get(j).start();
            }
            for (int j = 0; j < thread_number; j++) {
                t2.get(j).join();
            }
            t1.join();
        }
    }
}

Am I doing anything wrong? Or is there any hidden mechanism behind my fail, if so, is it possible to build a real code example that shows Java does not follow the sequential consistency?

By the way, my java version is OpenJDK Runtime Environment Corretto-11.0.8.10.1

  • [this](https://stackoverflow.com/questions/64983578/reading-a-stale-value-after-a-newer-value-was-read) has an example of jcstress that can prove what you are looking for – Eugene Jun 29 '21 at 02:44

2 Answers2

1

JMM is a weak memory model meaning that there is a separation between plain loads and stores and synchronization actions (e.g. write/read to a volatile variable or unlock/lock of lock). The JMM follows the SC-DRF model (Sequential Consistency for Data Race Free programs). SC-DRF means that if none of the possible executions of a program have a data race, the program will behave as if it is sequential consistent.

Keep in mind that if you are running on an X86, then 2 stores will not be reordered because of the X86 memory model (TSO). They could be executed out of order, but they will always retire and commit to the cache in program order (PO). The same goes for the 2 loads; loads will also be performed in PO even though under the hood they might be executed speculatively out of order. But this is impossible to detect because if the speculation fails, the CPU will flush the pipeline and retry.

Also the compiler could have optimized the code in such a way that the reordering won't happen because of the (intentional) data race.

This is where JCStress can help out: https://openjdk.java.net/projects/code-tools/jcstress.

pveentjer
  • 10,545
  • 3
  • 23
  • 40
1

As pveentjer already answered, JCStress can help out.

I just would like to add that one of the examples in JCStress source code is literally your case: BasicJMM_06_Causality.PlainReads.

So just study how it works and you will find out what nuances should be addressed when we try to reproduce some corner cases of JMM.