Jenny
Jenny

Reputation: 47

How volatile keyword works?

I'm reading about volatile keyword. After reading about volatile keyword, Going through below example for more understanding.

public class TaskRunner {
 
    private static int number;
    private static boolean ready;
 
    private static class Reader extends Thread {
 
        @Override
        public void run() {
            while (!ready) {
                Thread.yield();
            }
 
            System.out.println(number);
        }
    }
 
    public static void main(String[] args) {
        new Reader().start();
        number = 42;
        ready = true;
    }
}

What I've understood that, In Java application multiple threads can access shared data structure at any point of time. Some writes to it first time, some updates and some reads them and so on.

So while these happenings, every thread access the shared data structure's value from main memory only. But some times thread's operated value on shared data structure remains in its cache until the OS dont put it in main memory. So in that duration if any other thread access the shared data structure, will not get the updated value, which is updated by last thread and still in its cache.

Volatile is used, once shared data structure value is changed, should be moved to main memory first before it get accessed by any other thread. Is it correct understanding ?

What's scenario where thread still not getting updated value even after using volatile ?

Upvotes: 0

Views: 236

Answers (2)

rzwitserloot
rzwitserloot

Reputation: 102903

Java is rather high-level: As a language it is not designed for any particular CPU design. Furthermore, java compiles to bytecode, which is an intermediate product: Java does not offer, nor does it have the goal of, letting you write low-level CPU-architecture-specific operations.

And yet, caches are a low-level CPU architecture specific concept. Sure, every modern CPU has them, pretty much, but who knows what happens in 20 years?

So putting volatile in terms of what it does to CPU caches is skipping some steps.

volatile has an effect on your java code. That effect is currently implemented on most VMs I know of by sending the CPU some instructions about flushing caches.

It's better to deal with volatile at the java level itself, not at the 'well most VMs implement it like this' level - after all, that can change.

The way java is set up is essentially as follows:

If there are no comes-before relationships established between any 2 lines of code anywhere in java, then you should assume that java is like schroedinger's cat: Every thread both has and does not have a local cached copy of every field on every object loaded in the entire VM, and whenever you either write or read anything, the universe flips a coin, uses that to determine if you get the copy or not, and will always flip it to mess with you. During tests on your own machine, the coin flips to make the tests pass. During production on crunch weekend when millions of dollars are on the line, it flips to make your code fail.

The only way out is to ensure your code doesn't depend on the coin flip.

The way to do that is to use the comes-before rules, which you can review in the Java Memory Model.

volatile is one way to add them.

In the above code, without the volatile, the Reader thread may always use its local copy of ready, and thus will NEVER be ready, even if it has been many hours since your main set ready to true. In practice that's unlikely but the JMM says that a VM is allowed to coin flip here: It may have your Reader thread continue almost immediately, it may hold it up for an hour, it may hold it up forever. All legal - this code is broken, its behaviour depends on the coin flip which is bad.

Once you introduce volatile, though, you establish a comes-before relationship and now you're guaranteeing that Reader continues. Effectively, volatile both disables coinflips on the variable so marked and also established comes-before once reads/writes matter:

IF a thread observes an updated value in a volatile variable, THEN all lines that ran before whatever thread's code updated that variables have a comes-before relationship with all lines that will ran after the code in the thread that read the update.

So, to be clear:

Without any volatile marks here, it is legal for a VM to let Reader hang forever. It is also legal for a VM to let reader continue (to let it observe that ready is now true, whilst Reader STILL sees that number is 0 (and not 42), even after it passed the ready check! - but it doesn't have to, it is also allowed for the VM to have reader never pass the ready check, or to have it pass ready check and observe 42. A VM is free to do it however it wants; whatever seems fastest for this particular mix of CPU, architecture and phase of the moon right now.

With volatile, reader WILL end up continuing sooner rather than later, and once it has done so, it will definitely observe 42. But if you swap ready = true; and number = 42; that guarantee is no longer granted.

Upvotes: 1

v.ladynev
v.ladynev

Reputation: 19956

But some times thread's operated value on shared data structure remains in its cache until the OS dont put it in main memory. So in that duration if any other thread access the shared data structure, will not get the updated value, which is updated by last thread and still in its cache.

It is not the OS. There is a CPU instruction that is used by JVM to reset CPU cache. Honestly speaking, this claim is incorrect too, because Java Memory Model tells nothing about such instructions. This is one of the ways to implement volatile behaviour.

does volatile keword in java really have to do with caches?

Upvotes: 1

Related Questions