Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Java volatile visibility

I'm reading about the Java volatile keyword and have confusion about its 'visibility'.

A typical usage of volatile keyword is:

volatile boolean ready = false;
int value = 0;

void publisher() {
    value = 5;
    ready = true;
}

void subscriber() {
    while (!ready) {}
    System.out.println(value);
}

As explained by most tutorials, using volatile for ready makes sure that:

  • change to ready on publisher thread is immediately visible to other threads (subscriber);
  • when ready's change is visible to other thread, any variable update preceding to ready (here is value's change) is also visible to other threads;

I understand the 2nd, because volatile variable prevents memory reordering by using memory barriers, so writes before volatile write cannot be reordered after it, and reads after volatile read cannot be reordered before it. This is how ready prevents printing value = 0 in the above demo.

But I have confusion about the 1st guarantee, which is visibility of the volatile variable itself. That sounds a very vague definition to me.

In other words, my confusion is just on SINGLE variable's visibility, not multiple variables' reordering or something. Let's simplify the above example:

volatile boolean ready = false;

void publisher() {
    ready = true;
}

void subscriber() {
    while (!ready) {}
}

If ready is not defined volatile, is it possible that subscriber get stuck infinitely in the while loop? Why?

A few questions I want to ask:

  • What does 'immediately visible' mean? Write operation takes some time, so after how long can other threads see volatile's change? Can a read in another thread that happens very shortly after the write starts but before the write finishes see the change?
  • Visibility, for modern CPUs is guaranteed by cache coherence protocol (e.g. MESI) anyway, then why do we need volatile here?
  • Some articles say volatile variable uses memory directly instead of CPU cache, which guarantees visibility between threads. That doesn't sound a correct explain.
   Time : ---------------------------------------------------------->

 writer : --------- | write | -----------------------
reader1 : ------------- | read | -------------------- can I see the change?
reader2 : --------------------| read | -------------- can I see the change?

Hope I explained my question clearly.

like image 469
hangyuan Avatar asked Jul 18 '21 08:07

hangyuan


People also ask

How does volatile work in Java?

The volatile modifier is used to let the JVM know that a thread accessing the variable must always merge its own private copy of the variable with the master copy in the memory. Accessing a volatile variable synchronizes all the cached copied of the variables in the main memory.

Is volatile thread safe in Java?

Therefore, the volatile keyword does not provide thread safety when non-atomic operations or composite operations are performed on shared variables. Operations like increment and decrement are composite operations.

When should I use volatile in Java?

Yes, volatile must be used whenever you want a mutable variable to be accessed by multiple threads. It is not very common usecase because typically you need to perform more than a single atomic operation (e.g. check the variable state before modifying it), in which case you would use a synchronized block instead.

Where are volatile variables stored Java memory?

Volatile fields are instance or class (static) variables and are stored in the heap.

When to use volatile variable in Java?

When to Use volatile In order to expand more on the cache coherence, let's borrow one example from the book Java Concurrency in Practice: The TaskRunner class maintains two simple variables. In its main method, it creates another thread that spins on the ready variable as long as it's false.

Are volatile variables always visible to other threads?

The volatile variables are always visible to other threads. The volatile variable that is an object reference may be null. When a variable is not shared between multiple threads, you do not need to use the volatile keyword with that variable.

What is volatile keyword in Java?

Volatile Keyword in Java Volatile keyword is used to modify the value of a variable by different threads. It is also used to make classes thread safe. It means that multiple threads can use a method and instance of the classes at

What is the JMM rule for volatile variables in Java?

This is the volatile variable rule of the Java Memory Model ( JMM ). 5.1. Piggybacking Because of the strength of the happens-before memory ordering, sometimes we can piggyback on the visibility properties of another volatile variable. For instance, in our particular example, we just need to mark the ready variable as volatile:


1 Answers

Visibility, for modern CPUs is guaranteed by cache coherence protocol (e.g. MESI) anyway, so what can volatile help here?

That doesn't help you. You aren't writing code for a modern CPU, you are writing code for a Java virtual machine that is allowed to have a virtual machine that has a virtual CPU whose virtual CPU caches are not coherent.

Some articles say volatile variable uses memory directly instead of CPU cache, which guarantees visibility between threads. That doesn't sound a correct explain.

That is correct. But understand, that's with respect to the virtual machine that you are coding for. Its memory may well be implemented in your physical CPU's caches. That may allow your machine to use the caches and still have the memory visibility required by the Java specification.

Using volatile may ensure that writes go directly to the virtual machine's memory instead of the virtual machine's virtual CPU cache. The virtual machine's CPU cache does not need to provide visibility between threads because the Java specification doesn't require it to.

You cannot assume that characteristics of your particular physical hardware necessarily provide benefits that Java code can use directly. Instead, the JVM trades off those benefits to improve performance. But that means your Java code doesn't get those benefits.

Again, you are not writing code for your physical CPU, you are writing code for the virtual CPU that your JVM provides. That your CPU has coherent caches allows the JVM to do all kinds of optimizations that boost your code's performance, but the JVM is not required to pass those coherent caches through to your code and real JVM's do not. Doing so would mean eliminating a significant number of extremely valuable optimizations.

like image 63
David Schwartz Avatar answered Oct 13 '22 20:10

David Schwartz