0

Consider the following Java program:

static volatile int shared;

public static void main(final String[] args) {
  final Runnable r = () -> {
    shared = 1;
  };

  new Thread(r).start();
  new Thread(r).start();
}

Because shared is marked volatile, I want to say that this program is free from data races. However, how is this to be motivated based on the JLS (say, version 11)?

In chapter 17 we are told:

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.

I take this to be the definition of data races provided by the JLS. Then we have section 17.4.1 telling us:

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.

Ok, so we have conflicting accesses here as we have two writes to shared. Now we must have a happens-before relationship between the two writes, otherwise we have a race. I have, however, not managed to find why we have such relation here. Chapter 17 tells me that:

If an action x synchronizes-with a following action y, then we also have hb(x, y).

And the same chapter tells me:

A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order).

But I have not managed to find anything happens-before relating writes to volatile variables. Why is that?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
cic
  • 7,310
  • 3
  • 23
  • 35
  • Accesses to **volitile** variable are **never** subjet to **data race**. This is by definition of "data race" term. See e.g. given question: https://stackoverflow.com/questions/7805192/is-a-volatile-int-in-java-thread-safe. – Tsyvarev Mar 19 '19 at 13:37
  • 1
    @Tsyvarev: Sure, but I don't see how it "is by definition of 'data race'" -- from where do we get the happens-before relation between the two writes? or is there another reason the data race definition does not apply in our situation? – cic Mar 19 '19 at 21:07
  • Hm, I meant that in the cited phrase "When a program contains two conflicting accesses ... it is said to contain a data race." they mean accesses to "normal" variable. This phrase is not applicable to a *volatile* variable's accesses. I don't have the book right now, but I am pretty sure that such exception is clearly stated in the standard. – Tsyvarev Mar 19 '19 at 21:13
  • @Tsyvarev: I have not seen any such "clearly stated" exception. The "book" is available online, could you please provide a link to the relevant section where this exception is stated? – cic Mar 20 '19 at 09:45

1 Answers1

2

Accesses to a volatile variable are never subject to a data race.

It is not so obvious from the JLS, but in the phrase

(§17.4.1) 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.

the terms "read" and "write" are not generic ones, but are described in the next section "17.4.2 Actions" as accesses to a non-volatile variable:

Read (normal, or non-volatile). Reading a variable.

Write (normal, or non-volatile). Writing a variable.

In that section accesses to volatile variable are classified as a part of Synchronization actions, with different terms "Volatile read" and "Volatile write":

Volatile read. A volatile read of a variable.

Volatile write. A volatile write of a variable.

Because only (non-volatile) reads and writes can be conflicting, only those accesses may contain a data race. Volatile reads and writes can never be conflicting and can never contain a data race.

Community
  • 1
  • 1
Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • Oh, that's highly non-obvious... especially considering that they the use the terms before defining them. Thanks anyhow! – cic Mar 20 '19 at 12:27
  • Yes, I had needed to re-read the section "17.4" 3 times before I have found that relation. Even when I have been sure that it exists... – Tsyvarev Mar 20 '19 at 13:01