Search code examples
javamultithreadingjava-memory-modelhappens-before

JMM In Practice


Consider the following multithreaded code written in Java:

Shared variables:

         boolean n; // non-volatile
volatile boolean v; //     volatile

Thread 1:

v = true;
System.out.println("n=" + n);

Thread 2:

n = true;
System.out.println("v=" + v);

Assume initially n = v = false.

Now:

  • Does the output of v=false imply the output of n=true?
  • What would change if n were volatile?
  • What would change if n were java.util.List (so that n = true becomes n.add("something") and the output n=true transforms into ["something"])?
  • UPD3: What if v were AtomicBoolean and all reads of and writes to it performed with the compareAndSet semantic?

Could you argue your position according to the Java Memory Model?

UPD: Please treat System.out.println("n=" + n) as just a read of n. The same for v.

UPD2: Could you provide some analysis of the 1st and 4th case as it shown in JSR-133 sec. 8?


Solution

  • There's really three ways that code can execute:

    // Thread 1 runs first
    T1: v = true;
    T1: System.out.println("n=" + n);  // prints n=false
    
    // Thread 2 runs second
    T2: n = true;
    T2: System.out.println("v=" + v);  // prints v=true
    
    // They run in parallel, so assignments first, in any order
    T1: v = true;
    T2: n = true;
    
    // Print statements second, in any order
    T1: System.out.println("n=" + n);  // may print n=true or n=false (depends on CPU caching)
                                       // will print n=true if n is volatile
    T2: System.out.println("v=" + v);  // prints v=true
    
    // Thread 2 runs first
    T2: n = true;
    T2: System.out.println("v=" + v);  // prints v=false
    
    // Thread 1 runs second
    T1: v = true;
    T1: System.out.println("n=" + n);  // may print n=true or n=false (depends on CPU caching)
                                       // will print n=true if n is volatile
    

    Does the output of v=false imply the output of n=true?

    No. As you can see in 3rd scenario, n may print either value.

    What would change if n were volatile?

    As commented, n will print true in scenario 2 and 3, instead of being indeterminate.

    What would change if n were java.util.List (so that n = true becomes n.add("something") and the output n=true transforms into ["something"])?

    This presumes that n is already a List before the scenarios start, so the volatility of n doesn't matter.

    Whether the print of n will see the inserted value depends on the type of list. If the list of not concurrent, the answer is the same as for question 1: It may or may not see the new value. Examples of non-concurrent lists:

    If the list is concurrent, it will see the new value. Examples of concurrent lists: