Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why and how does volatile imply atomic reads/writes?

First off, I'm aware that volatile does not make multiple operations (as i++) atomic. This question is about a single read or write operation.

My initial understanding was that volatile only enforces a memory barrier (i.e. other threads will be able to see updated values).

Now I've noticed that JLS section 17.7 says that volatile additionally makes a single read or write atomic. For instance, given two threads, both writing a different value to a volatile long x, then x will finally represent exactly one of the values.

I'm curious how this is possible. On a 32 bit system, if two threads write to a 64 bit location in parallel and without "proper" synchronization (i.e. some kind of lock), it should be possible for the result to be a mixup. For clarity, let's use an example in which thread 1 writes 0L while thread 2 writes -1L to the same 64 bit memory location.

T1 writes lower 32 bit
T2 writes lower 32 bit
T2 writes upper 32 bit
T1 writes upper 32 bit

The result could then be 0x0000FFFF, which is undesirable. How does volatile prevent this scenario?

I've also read elsewhere that this does, typically, not degrade performance. How is it possible to synchronize writes with only a minor speed impact?

like image 911
mafu Avatar asked Jul 28 '14 10:07

mafu


People also ask

Can a volatile variable be read and write?

You can use a volatile variable if you want to read and write long and double variable automatically. It can be used as an alternative way of achieving synchronization in Java. All reader threads will see the updated value of the volatile variable after completing the write operation.

Does atomic imply volatile?

The keyword volatile does not imply atomic access and has no bearing on atomic access whatsoever.

What is difference between volatile and atomic?

Volatile and Atomic are two different concepts. Volatile ensures, that a certain, expected (memory) state is true across different threads, while Atomics ensure that operation on variables are performed atomically.

Why are read and write Atomic?

Generally, you can summarize atomic as "one at a time". For example, when accessing or mutating a property is atomic, it means that only one read or write operation can be performed at a time. If you have a program that reads a property atomically, this means that the property cannot change during this read operation.


1 Answers

Your statement that volatile only enforces a memory barrier (in the meaning, flushes the processor cache) is false. It also implies a happens-before relationship of read-write combinations of volatile values. For example:

class Foo {
  volatile boolean x;
  boolean y;

  void qux() {
    x = true; // volatile write
    y = true;
  }

  void baz() {
    System.out.print(x); // volatile read
    System.out.print(" ");
    System.out.print(y);
  }
}

When you run both methods from two threads, the above code will either print true false, true true or false false but never false true. Without the volatile keyword, you are not guaranteed the later condition because the JIT compiler might reorder statements.

The same way as the JIT compiler can assure this condition, is can guard 64-bit value reads and writes in the assembly. volatile values are treated explicitly by the JIT compiler to assure their atomicity. Some processor instruction sets support this directly by specific 64-bit instructions, otherwise the JIT compiler emulates it.

The JVM is more complex as you might expect it to be and it is often explained without full scope. Consider reading this excellent article which covers all the details.

like image 135
Rafael Winterhalter Avatar answered Oct 05 '22 05:10

Rafael Winterhalter