I'm reading Chapter 17. Threads and Locks of JLS and the following statement about sequential consistency in Java seems incorrect to me:
If a program has no data races, then all executions of the program will appear to be sequentially consistent.
They define a data race as:
When a program contains two conflicting accesses (§17.4.1) that are not ordered by a happens-before relationship, it is said to contain a data race.
They define conflicted accesses as:
Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write.
And finally they have following about happens-before relationship:
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
My problem with the 1st statement is that I think I can come up with a Java program which has no data races and allows sequentially inconsistent executions:
// Shared code
volatile int vv = 0;
int v1 = 0;
int v2 = 0;
// Thread1 Thread2
v1 = 1;
v2 = 2;
vv = 10; while(vv == 0) {;}
int r1 = v1;
int r2 = v2;
System.out.println("v1=" + r1 + " v2=" + r2);
v1 = 3;
v2 = 4;
vv = 20;
In the code above I also showed with indentation how the threads' code is interleaved in runtime.
So, as I understand, this program:
- has no data races: reads of v1 and v2 in Thread2 are synchronized-with writes in Thread1
- can output
v1=1 v2=4(which violates sequential consistency).
As a result, the initial statement from JLS
If a program has no data races, then all executions of the program will appear to be sequentially consistent.
seems incorrect to me.
Am I missing something or did I make a mistake somewhere?
EDIT: user chrylis-cautiouslyoptimistic correctly pointed out that the code I gave can output v1=1 v2=4 with sequential consistency — the lines in threads' code simply should be interleaved a little bit differently.
So here is the slightly modified code (I've changed the order of reads) for which sequential consistency cannot output v1=1 v2=4, but everything still applies.
// Shared code
volatile int vv = 0;
int v1 = 0;
int v2 = 0;
// Thread1 Thread2
v1 = 1;
v2 = 2;
vv = 10; while(vv == 0) {;}
int r2 = v2;
int r1 = v1;
System.out.println("v1=" + r1 + " v2=" + r2);
v1 = 3;
v2 = 4;
vv = 20;