Roland Roland - 5 months ago 13
Java Question

Reordering of reads

Suppose there are two threads without synchronization, one sets

n = 1
another executes

In the following "read" always refers to a read of field

public class MyClass
public int n = 0;

public void method() {
System.out.println(n); //read 1
System.out.println(n); //read 2

Would the following output be possible?


The answer is yes because even though read 1 happens-before read 2, it is nevertheless possible for read 2 to be re-ordered before read 1 because it wouldn't change the semantics of intra-thread execution.

Is this reasoning correct?


Happens-before does not imply the order for two arbitrary operations. To be more precise, the most important thing that happens-before does is tying up writes and reads in happens-before consistency. Notably, it tells what writes can a read observe: the last write in happens-before order, or any other write not ordered in happens-before (race). Note that two consecutive reads may see different values obtained from different (racy) writes, without violating that requirement.

E.g. JLS 17.4.5 says:

"It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal."

Data races are creepy like that: racy reads can return surprising data on each read, and Java memory model captures that. So the more precise answer is that an execution that produces (1, 0) is not violating Java Memory Model constraints (sync order consistency, sync order - program order consistency, happens-before consistency, causality requirements), and therefore allowed.

Implementation-wise: on hardware, both loads can be started and/or arrive to memory subsystem at different times, regardless of their "program order", because they are indepenent; in compilers, instruction scheduling may also disregard the program order for the independent reads, exposing loads to hardware in "counter-intuitive" order.

If you want reads to be observed in the program order, you need a stronger property. JMM gives that property to synchronization actions (in your example, making a variable volatile would make that), which ties the actions in the total synchronization order that is consistent with program order. In that case, (1, 0) would be prohibited.