alfer
alfer

Reputation: 375

Java volatile and happens-before scope

The tutorial http://tutorials.jenkov.com/java-concurrency/volatile.html says

Reads from and writes to other variables cannot be reordered to occur after a write to a volatile variable, if the reads / writes originally occurred before the write to the volatile variable. The reads / writes before a write to a volatile variable are guaranteed to "happen before" the write to the volatile variable.

What is meant by "before the write to the volatile variable"? Does it mean previous read/writes in the same method where we are writing to the volatile variable? Or is it a larger scope (also in methods higher up the call stack)?

Upvotes: 1

Views: 490

Answers (3)

pveentjer
pveentjer

Reputation: 11392

The JMM is defined in terms of happens before relation which we'll call ->. If a->b, then the b should see everything of a. This means that there are constraints on reordering loads/stores.

If a is a volatile write and b is a subsequent volatile read of the same variable, then a->b. This is called the volatile variable rule.

If a occurs before b in the code, then a->b. This is called the program order rule.

If a->b and b->c, then a->c. This is called the transitivity rule.

So lets apply this to a simple example:

int a;
volatile int b;

thread1(){
    a=1;
    b=1
}

thread2(){
  int rb=b;
  int ra=a;
  if(rb==1 and ra==0) print("violation");
}

So the question is if thread2 sees rb=1,will it see ra=1?

a=1->b=1 due to program order rule.

b=1->rb=b (since we see the value 1) due to the volatile variable rule.

rb=b->ra=a due to program order rule.

Now we can apply the transitivity rule twice and we can conclude that that a=1->ra=a. And therefor ra needs to be 1.

This means that:

  • a=1 and b=1 can't be reordered.
  • rb=b and ra=a can't be reordered

otherwise we could end up with an rb=1 and ra=0.

Upvotes: 1

Prashant Pandey
Prashant Pandey

Reputation: 4652

The JVM ensures that writes to a volatile variable happens-before any reads from it. Take two threads. It's guarateed that for a single thread, the execution follows an as-if-serial semantics. Basically you can assume that there is an implicit happens-before relationship b/w two executions in the same thread (the compiler is still free to reorder instructions). Basically a single thread has a total order b/w its instructions governed by the happens-before relationship trivially.

A multi-threaded program has many such partial orders (every thread has a total order in the local instruction set but there is no order globally across threads) but not a total order b/w the global instruction set. Synchronisation is all about giving your program as much total order as possible.

Coming back to volatile variables, when a thread reads from it, the JVM ensures that all writes to it happened before the read. Now because of this order, everything the writing thread did before it wrote to the variable become visible to the thread reading from it. So yes, to answer your question, even variables up in the call stack should be visible to the reading thread.

I'll try to draw a visual picture. The two threads can be imagined as two parallel rails, and write to a volatile variable can be one of the sleepers b/w them. You basically get a

        A -----
              |
              |
              ------- B

shaped total order b/w the two threads of execution. Everything in A before the sleeper should be visible to B after the sleeper because of this total order.

Upvotes: 0

Vitalii
Vitalii

Reputation: 481

JVM can reorder operations. For example if we have i, j variables and code

i = 1;
j = 2;

JVM can run this in reordered manner

j = 2;
i = 1;

But if the j variable marked as volatile then JVM runs operations only as

i = 1;
j = 2;

write to i "happens before the write to the volatile variable" j.

Upvotes: 2

Related Questions