Deep understanding of Java volatility

Can Java output 1, 0 ? I tested it very intensively and I cannot get this conclusion. I get only 1, 1 or 0, 0 or 0, 1 .

 public class Main { private int x; private volatile int g; // Executed by thread #1 public void actor1(){ x = 1; g = 1; } // Executed by thread #2 public void actor2(){ put_on_screen_without_sync(g); put_on_screen_without_sync(x); } } 

Why?

In my opinion, you can get 1, 0 . My reasoning. g is volatile, therefore it provides preservation of memory order. So it looks like this:

 actor1: (1) store(x, 1) (2) store(g, 1) (3) memory_barrier // on x86 

and I see the following situation: reorder store(g, 1) to store(x,1) (memory_barrier after (2)). Now run thread # 2. So g = 1, x = 0 . Now we are waiting for the exit. What is wrong in my reasoning?

+3
java memory-order
source share
3 answers

Any actions before volatile recording occurs earlier (HB), any subsequent volatile reading of the same variable. In your case, writing to x occurs before writing to g (due to the order of the program).

Thus, there are only three possibilities:

  • actor2 starts first, and x and g - 0 - output 0,0
  • actor1 starts first, and x and g are equal to 1 due to what happens before the HB relation - output 1.1
  • methods are launched at the same time, and only x=1 (not g=1 ) is executed, and the output can be either 0.1 or 0.0 (without volatile writing, so there is no guarantee).
+2
source share

No, It is Immpossible. According to JMM, everything that was visible to stream 1 when writing to a volatile field becomes visible to stream 2 when reading this field.

Below is an example similar to your specified here :

 class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() { if (v == true) { //uses x - guaranteed to see 42. } } } 
+2
source share

No, and in fact this volatile property is used in classes like ConcurrentHashMap to implement a happy path without blocking, something like this:

 volatile int locked = 0; ... void mutate() { if (Unsafe.compareAndSwapInt(locked,0,1)) { /*this isn't exactly how you call this method, but the point stands: if we read 0, we atomically replace it with 1 and continue on the happy path */ //we are happy //so we mutate the structure and then locked = 0; } else { //contended lock, we aren't happy } } 

Since recordings before a volatile recording cannot be reordered after a volatile recording, and reading after a volatile reading cannot be reordered before a change in volatility, such code really works as a “locked lock”.

0
source share

All Articles