4

I'm having problems understanding how JMM relates to possible instructions reordering. For example, let's consider the following code snippet:

volatile boolean t1HasArrived = false, t2HasArrived = false; // In thread 1 t1HasArrived = true; while (!t2HasArrived) ; // In thread 2 t2HasArrived = true; while (!t1HasArrived) ; 

Now, I want to believe that this code implements Barrier synchronization for two threads. But I'm not sure about it. The thing that gives me doubts is read/writes reordering: is there anything in JMM that would prevent compiler or CPU to rearrange execution path of the code like the code snippet below? And if not, how do you actually prove that such reordering is allowed?

// In thread 1 while (!t2HasArrived) ; t1HasArrived = true; // In thread 2 while (!t1HasArrived) ; t2HasArrived = true; 

Note, that I'm not trying to implement locks-free Barrier. This is just an example that came to my mind after I started thinking about instructions reordering. I just want to understand how to apply JMM rules to it. It is relatively easy to reason about piece of code when there is only one volatile variable/lock involved, but when there are several, things become complicated.

2
  • 1
    I am not too sure about your question. But from the java concurrency book, i believe it was mentioned that reading a volatile variable is like the same as entering a synchronized block, that means the value of the volatile variable modified from another thread will become visible to you, and the order of code execution from another thread will also become as if they were executed in order. Commented Nov 3, 2015 at 0:07
  • 1
    Leonid I agree with CChi it's hard to tell what question you are looking to have answered specifically Commented Nov 3, 2015 at 0:10

2 Answers 2

4

Volatile variables cannot be reordered with each other by the JMM.

In your case, you have a volatile store followed by a volatile load, and those cannot be reordered into a load followed by a store. This is true for all versions of Java.

See The JSR-133 Cookbook for Compiler Writers for specifics.


Lasciate ogni speranza, voi ch’entrate.

From the JSR-133 specification:

§5 Definitions

Inter-thread Actions An inter-thread action is an action performed by one thread that can be detected or directly influenced by another thread. Inter-thread actions include reads and writes of shared variables and synchronization actions, such as locking or unlocking a monitor, reading or writing a volatile variable, or starting a thread.

Synchronization Actions Synchronization actions include locks, unlocks, reads of and writes to volatile variables, actions that start a thread, and actions that detect that a thread is done.

§7.3 Well-Formed Executions

We only consider well-formed executions. An execution E = 〈P, A, po→, so→, W, V, sw→, hb→〉 is well formed if the following conditions are true:

  1. Synchronization order is consistent with program order and mutual exclusion. Having synchronization order is consistent with program order implies that the happensbefore order, given by the transitive closure of synchronizes-with edges and program order, is a valid partial order: reflexive, transitive and antisymmetric. Having synchronization order consistent with mutual exclusion means that on each monitor, the lock and unlock actions are correctly nested.
Sign up to request clarification or add additional context in comments.

9 Comments

While your assertion is correct, note that your answer is based on a recommendation for implementing the Java memory model which is much stricter than what the JMM permits. Referecning this cookbook is therefore not really proving anything.
@Rafael Please edit the answer and add a reference if you have a better source!
Well, I guess this answers my question from a pragmatic point of view, but I'm still curious what words in JMM prohibit such reordering.
@Leonid I just added a couple of excerpts from the JSR-133. They are a bit technical, I hope you can read them.
@Tomas This would require to replace the entire answer. As I said, the cookbook is an instruction to implementators for a sensible implementation that widely overfullfils the JMM. The JMM argues in form of orderings, not memory fences.
|
3

The JMM defines reordering restrictions as the transitive closure of certain orderings of program instructions. If an ordering exists between a write and a read, the JVM is required to return the value according to this ordering.

In your case, a synchronization order for any volatile read observing the value of a volatile write is implied by the fields being volatile. A synchronization order, requires a thread to observe all written fields that were comitted previous to the volatile write after the volatile read in the order of the program.

This implies that whenever a volatile field is read, the program order of your application requires the volatile writes to be comitted according to program order what induces a happens-before relationship of the writes to the reads. Thus, the reordering that you suggest as an optimzation is invalid and the JMM guarantees the visibility that your original source code implies.

I recently gave a presentation on the JMM if you want to understand this in greater detail (time - 7 hours, 27 minutes).

2 Comments

The link you've provided leads to 8 hours long JavaOne LIVE video. At 7:27 you can see Stuart Marks getting ready for his "20 years of APIs" talk (just finished watching it, nice historical talk), so, I guess, the timing of your talk has shifted.
7 hours 27 minutes. JavaOne unfortunately uploaded the uncut videos only.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.