2

I'm now reading Java Language Specification.

§17.4.5-1 said

In this execution, the reads see writes that occur later in the execution order. This may seem counterintuitive, but is allowed by happens-before consistency. Allowing reads to see later writes can sometimes produce unacceptable behaviors.

§17.4.8-1 said

Although allowing reads to see writes that come later in the execution order is sometimes undesirable, it is also sometimes necessary.

Also 17.4.8-1 gives a strange example.

Why can reads see writes come later possible?

If it's really possible, how can I reproduce it in java code?

EDIT

This is not duplicate question. That question just asked 17.4.5-1, I can understand 17.4.5-1 because compiler may reorder them. But what about 17.4.8-1? It's under Executions and Causality Requirements. According to definition of execution order, no one can reorder

r1 = x; // write

and

if (r1 != 0) // read

So that y = 1 must happens the last.

Dean Xu
  • 4,438
  • 1
  • 17
  • 44
  • 1
    As far as I understand, it's not saying a race condition would actually be possible in that case. It's saying that *happens-before* alone is insufficient to guarantee correctness, hence the need for causality requirements. – shmosel Aug 09 '18 at 02:56
  • The JIT and even the CPU can re-order instructions in the interests of optimisations. This can mean that a read which appears to execute first can see a write which would appear to be executed later. This is very rare, a more common behaviour is lazySet where a read sees an older value after writing to memory. NOTE: This should never happen for regular Java code, so I am not sure if it releates to the JLS. – Peter Lawrey Aug 09 '18 at 07:54
  • 2
    @PeterLawrey But the sample 17.4.8-1 can't explain by reordering. – Dean Xu Aug 09 '18 at 09:07
  • @shmosel You may right. It is just a paradox in theory. That is why I can't find any runnable example for it. – Dean Xu Aug 09 '18 at 09:08
  • "This is not duplicate question. That question just asked...": for clarity, add a link to "that question". – Raedwald Aug 13 '18 at 16:36

1 Answers1

2

The example

Table 17.4.8-A

      Thread 1                  Thread 2
r1 = x;                    r2 = y;
if (r1 != 0) y = 1;        if (r2 != 0) x = 1;

is possible on an architecture that has speculative execution. So the CPU encounters the conditional branch when the value requested from the main memory has not arrived yet and decides to execute the conditional code and roll it back in case the condition is not fulfilled.

When the value arrives at the CPU core, it’s the value written by the other thread, so the condition is fulfilled and the changes are kept.

You can not reproduce this in Java code, as the specification continues with the explanation that such a scenario is not allowed for Java code. It’s an example of what would be allowed, if we only had happens-before consistency. But Java additionally forbids “out of thin air values”. So, JVM implementations for architectures supporting such speculative execution must ensure that it is limited to variables not seen by other threads (or disable it completely).

Holger
  • 285,553
  • 42
  • 434
  • 765