ChatGPT解决这个技术问题 Extra ChatGPT

What is the volatile keyword useful for?

At work today, I came across the volatile keyword in Java. Not being very familiar with it, I found this explanation.

Given the detail in which that article explains the keyword in question, do you ever use it or could you ever see a case in which you could use this keyword in the correct manner?


B
Basil Bourque

volatile has semantics for memory visibility. Basically, the value of a volatile field becomes visible to all readers (other threads in particular) after a write operation completes on it. Without volatile, readers could see some non-updated value.

To answer your question: Yes, I use a volatile variable to control whether some code continues a loop. The loop tests the volatile value and continues if it is true. The condition can be set to false by calling a "stop" method. The loop sees false and terminates when it tests the value after the stop method completes execution.

The book "Java Concurrency in Practice," which I highly recommend, gives a good explanation of volatile. This book is written by the same person who wrote the IBM article that is referenced in the question (in fact, he cites his book at the bottom of that article). My use of volatile is what his article calls the "pattern 1 status flag."

If you want to learn more about how volatile works under the hood, read up on the Java memory model. If you want to go beyond that level, check out a good computer architecture book like Hennessy & Patterson and read about cache coherence and cache consistency.


This answer is correct, but incomplete. It omits an important property of volatile that came with the new Java Memory Model defined in JSR 133: that when a thread reads a volatile variable it sees not only the value last written to it by some other thread, but also all other writes to other variables that were visible in that other thread at the time of the volatile write. See this answer and this reference.
For beginners, I'd request you to demonstrate with some code (please?)
The article linked in the question has code examples.
I think the link 'Hennessy & Patterson' is broken. And the link to 'the Java memory model' actually leads to Oracle's Java Language Specification 'Chapter 17. Threads and Locks'.
@fefrei: “immediately” is a colloquial term. Of course, that can’t be guaranteed when neither, execution timing nor thread scheduling algorithms, are actually specified. The only way for a program to find out whether a volatile read is subsequent to a particular volatile write, is by checking whether the seen value is the expected written one.
9
9 revs, 2 users 92%

“… the volatile modifier guarantees that any thread that reads a field will see the most recently written value.” - Josh Bloch

If you are thinking about using volatile, read up on the package java.util.concurrent which deals with atomic behaviour.

The Wikipedia post on a Singleton Pattern shows volatile in use.


Why is there both volatile and synchronized keywords?
The Wikipedia article on a Singleton Pattern has changed a lot since and doesn't feature said volatile example any longer. It can be found in an archived version.
@ptkato Those two keywords serve completely different purposes, so the question doesn't make much sense as a comparison, although they are both related to concurrency. It's like saying "Why are there both void and public keywords".
So... in a nutshell, volatile is kinda similar with static on class ? where multiple instances of a class can share the same variable/property.
@Aruman I don't think that's correct. A static variable might also have to be volatile in case there are multiple threads reading it, the two are unrelated.
M
Marco Luzzara

Volatile(vɒlətʌɪl): Easily evaporated at normal temperatures

Important point about volatile:

Synchronization in Java is possible by using Java keywords synchronized and volatile and locks. In Java, we can not have synchronized variable. Using synchronized keyword with a variable is illegal and will result in compilation error. Instead of using the synchronized variable in Java, you can use the java volatile variable, which will instruct JVM threads to read the value of volatile variable from main memory and don’t cache it locally. If a variable is not shared between multiple threads then there is no need to use the volatile keyword.

source

Example usage of volatile:

public class Singleton {
    private static volatile Singleton _instance; // volatile variable
    public static Singleton getInstance() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null)
                    _instance = new Singleton();
            }
        }
        return _instance;
    }
}

We are creating instance lazily at the time the first request comes.

If we do not make the _instance variable volatile then the Thread which is creating the instance of Singleton is not able to communicate to the other thread. So if Thread A is creating Singleton instance and just after creation, the CPU corrupts etc, all other threads will not be able to see the value of _instance as not null and they will believe it is still assigned null.

Why does this happen? Because reader threads are not doing any locking and until the writer thread comes out of a synchronized block, the memory will not be synchronized and value of _instance will not be updated in main memory. With the Volatile keyword in Java, this is handled by Java itself and such updates will be visible by all reader threads.

Conclusion: volatile keyword is also used to communicate the content of memory between threads.

Example usage of without volatile:

public class Singleton {    
    private static Singleton _instance;   //without volatile variable
    public static Singleton getInstance() {   
        if (_instance == null) {  
            synchronized(Singleton.class) {  
                if (_instance == null) 
                    _instance = new Singleton(); 
            } 
        }
        return _instance;  
    }
}

The code above is not thread-safe. Although it checks the value of instance once again within the synchronized block (for performance reasons), the JIT compiler can rearrange the bytecode in a way that the reference to the instance is set before the constructor has finished its execution. This means the method getInstance() returns an object that may not have been initialized completely. To make the code thread-safe, the keyword volatile can be used since Java 5 for the instance variable. Variables that are marked as volatile get only visible to other threads once the constructor of the object has finished its execution completely.
Source

https://i.stack.imgur.com/bgHrU.png

volatile usage in Java:

The fail-fast iterators are typically implemented using a volatile counter on the list object.

When the list is updated, the counter is incremented.

When an Iterator is created, the current value of the counter is embedded in the Iterator object.

When an Iterator operation is performed, the method compares the two counter values and throws a ConcurrentModificationException if they are different.

The implementation of fail-safe iterators is typically light-weight. They typically rely on properties of the specific list implementation's data structures. There is no general pattern.


"The fail-fast iterators are typically implemented using a volatile counter" - no longer the case, too costly: bugs.java.com/bugdatabase/view_bug.do?bug_id=6625725
are the double checking for _instance safe? i thought they are not safe even with volatile
" which will instruct JVM threads to read value of volatile variable from main memory and don’t cache it locally." good point
For thread-safety one could go with private static final Singleton _instance; as well.
@Chris311, sure, the static final field, it's thread safe.
N
Nayantara Jeyaraj

volatile is very useful to stop threads.

Not that you should be writing your own threads, Java 1.6 has a lot of nice thread pools. But if you are sure you need a thread, you'll need to know how to stop it.

The pattern I use for threads is:

public class Foo extends Thread {

  private volatile boolean close = false;

  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

In the above code segment, the thread reading close in the while loop is different from the one that calls close(). Without volatile, the thread running the loop may never see the change to close.

Notice how there's no need for synchronization


I wonder why that is even necessary. Isn't that only necessary if other threads have to react on the status change of this thread in such a way that the threads synchronization is at danger?
@Jori, you need volatile because the thread reading close in the while loop is different from the one that calls close(). Without volatile, the thread running the loop may never see the change to close.
would you say there is an advantage between stopping a thread like that or using Thread#interrupt() and Thread#isInterrupted() methods ?
@Pyrolistical - Have you observed the thread never seeing the change in practice? Or can you extend the example to reliably trigger that issue? I'm curious because I know I've used (and seen others using) code that's basically identical to the example but without the volatile keyword, and it always seems to work fine.
@aroth: with today’s JVMs, you can observe that in practice, even with the simplest examples, however, you can’t reliably reproduce this behavior. With more complex applications, you sometimes have other actions with memory visibility guarantees within you code which make it happen to work, which is especially dangerous as you don’t know why it works and a simple, apparently unrelated change in your code can break your application…
S
Supun Wijerathne

A variable declared with volatile keyword, has two main qualities which make it special.

If we have a volatile variable, it cannot be cached into the computer's(microprocessor) cache memory by any thread. Access always happened from main memory. If there is a write operation going on a volatile variable, and suddenly a read operation is requested, it is guaranteed that the write operation will be finished prior to the read operation.

Two above qualities deduce that

All the threads reading a volatile variable will definitely read the latest value. Because no cached value can pollute it. And also the read request will be granted only after the completion of the current write operation.

And on the other hand,

If we further investigate the #2 that I have mentioned, we can see that volatile keyword is an ideal way to maintain a shared variable which has 'n' number of reader threads and only one writer thread to access it. Once we add the volatile keyword, it is done. No any other overhead about thread safety.

Conversly,

We can't make use of volatile keyword solely, to satisfy a shared variable which has more than one writer thread accessing it.


This explains the difference between volatile and synchronized.
This is, sadly, incorrect. "Volatile" does not control cache and does not provide any magic instant global update for memory views of other CPUs. "Volatile" simply ensures that whenever a reference to the variable is done (either read or write), JVM performs a reference to the assigned address of the variable in virtual memory space, rather than to a value stored in a register or in some other convenient shadow location (such as stack) selected by the optimizer, nor does it skip a reference on the judgement of the optimizer.
Without "volatile", an instruction such as "for (...) {a += b + c;}" may not refer memory locations at all, just keeping "a", "b" and "c" in registers for the whole duration of the loop. When a value is written by CPU to a virtual memory address (or for that matter, corresponding physical memory address), the update does not become instantly visible to other CPUs, nor is it flushed immediatelly to RAM [*].
The update is simply put to the cache of the local CPU and then is queued to the inter-CPU interconnect that implements memory coherency protocol (such as MESI), and the protocol message starts travelling to other CPUs, eventually causing their caches to be updated too. This takes short, but non-zero time. In the meanwhile, other CPUs remain unaware that an update has happened. If CPU1 updated volatile variable X, and CPU2 read it a jiffy later, CPU2 may find either old value for X or new value for X.
On the write side, the difference between "volatile" and "non-volatile" is that for "volatile" CPU2 will see an update a nanosecond or so later, whereas for "non-volatile" the delay in update is unpredictable and depends on the optimizer. On the read side, the difference is that for "volatile" a reference to the variable in the program code forces a reference to the assigned variable location in virtual memory. Whereas for "non-volatile" the optimizer may choose to skip making such a reference.
D
Dave L.

One common example for using volatile is to use a volatile boolean variable as a flag to terminate a thread. If you've started a thread, and you want to be able to safely interrupt it from a different thread, you can have the thread periodically check a flag. To stop it, set the flag to true. By making the flag volatile, you can ensure that the thread that is checking it will see it has been set the next time it checks it without having to even use a synchronized block.


y
ykaganovich

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.


D
Donatello Boccaforno

No one has mentioned the treatment of read and write operation for long and double variable type. Reads and writes are atomic operations for reference variables and for most primitive variables, except for long and double variable types, which must use the volatile keyword to be atomic operations. @link


To make it even more clearer, there is NO NEED to set a boolean volatile, because the read and write of a boolean IS ALREADY atomic.
@KaiWang you don't need to use volatile on booleans for atomicity purposes. But you certainly might for visibility reasons. Is that what you meant to say?
y
yoAlex5

Volatile

volatile -> synchronized[About]

volatile says for a programmer that the value always will be up to date. The problem is that the value can be saved on different types of hardware memory. For example it can be CPU registers, CPU cache, RAM... СPU registers and CPU cache belong to CPU and can not share a data unlike of RAM which is on the rescue in multithreading envirompment

https://i.stack.imgur.com/1EPWG.png

volatile keyword says that a variable will be read and written from/to RAM memory directly. It has some computation footprint

Java 5 extended volatile by supporting happens-before[About]

A write to a volatile field happens-before every subsequent read of that field.

Read is after write

volatile keyword does not cure a race condition situation when several threads can write some values simultaneously. The answer is synchronized keyword[About]

As a result it safety only when one thread writes and others just read the volatile value


W
Water

In my opinion, two important scenarios other than stopping thread in which volatile keyword is used are:

Double-checked locking mechanism. Used often in Singleton design pattern. In this the singleton object needs to be declared volatile. Spurious Wakeups. Thread may sometimes wake up from wait call even if no notify call has been issued. This behavior is called spurious wakeup. This can be countered by using a conditional variable (boolean flag). Put the wait() call in a while loop as long as the flag is true. So if thread wakes up from wait call due to any reasons other than Notify/NotifyAll then it encounters flag is still true and hence calls wait again. Prior to calling notify set this flag to true. In this case the boolean flag is declared as volatile.


The whole #2 section seems very confused, it is conflating lost notifications, spurious wakeups, and memory visibility issues. Also if all usages of the flag are in synchronized then volatile is redundant. I think i get your point but spurious wakeup is not the correct term. Please clarify.
C
CJay

Assume that a thread modifies the value of a shared variable, if you didn't use volatile modifier for that variable. When other threads want to read this variable's value, they don't see the updated value because they read the variable's value from the CPU's cache instead of RAM memory. This problem also known as Visibility Problem.

By declaring the shared variable volatile, all writes to the counter variable will be written back to main memory immediately. Also, all reads of the counter variable will be read directly from main memory.

public class SharedObject {
    public volatile int sharedVariable = 0;
}

With non-volatile variables there are no guarantees about when the Java Virtual Machine (JVM) reads data from main memory into CPU caches, or writes data from CPU caches to main memory. This can cause several problems which I will explain in the following sections.

Example:

Imagine a situation in which two or more threads have access to a shared object which contains a counter variable declared like this:

public class SharedObject {
    public int counter = 0;
}

Imagine too, that only Thread 1 increments the counter variable, but both Thread 1 and Thread 2 may read the counter variable from time to time.

If the counter variable is not declared volatile there is no guarantee about when the value of the counter variable is written from the CPU cache back to main memory. This means, that the counter variable value in the CPU cache may not be the same as in main memory. This situation is illustrated here:

https://i.stack.imgur.com/L57nd.png

The problem with threads not seeing the latest value of a variable because it has not yet been written back to main memory by another thread, is called a "visibility" problem. The updates of one thread are not visible to other threads.


does the main thread (parent thread) in general updates everything in ram directly? Or does the main thread also a cache
Also in general (non-multithreading scenarios) in Java, when is the ram updated from Cache?
A
Arjan Tijms

You'll need to use 'volatile' keyword, or 'synchronized' and any other concurrency control tools and techniques you might have at your disposal if you are developing a multithreaded application. Example of such application is desktop apps.

If you are developing an application that would be deployed to application server (Tomcat, JBoss AS, Glassfish, etc) you don't have to handle concurrency control yourself as it already addressed by the application server. In fact, if I remembered correctly the Java EE standard prohibit any concurrency control in servlets and EJBs, since it is part of the 'infrastructure' layer which you supposed to be freed from handling it. You only do concurrency control in such app if you're implementing singleton objects. This even already addressed if you knit your components using frameworkd like Spring.

So, in most cases of Java development where the application is a web application and using IoC framework like Spring or EJB, you wouldn't need to use 'volatile'.


b
bwegs

volatile only guarantees that all threads, even themselves, are incrementing. For example: a counter sees the same face of the variable at the same time. It is not used instead of synchronized or atomic or other stuff, it completely makes the reads synchronized. Please do not compare it with other java keywords. As the example shows below volatile variable operations are also atomic they fail or succeed at once.

package io.netty.example.telnet;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

Even you put volatile or not results will always differ. But if you use AtomicInteger as below results will be always same. This is same with synchronized also.

    package io.netty.example.telnet;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }

A
Abhishek Luthra

While I see many good Theoretical explanations in the answers mentioned here, I am adding a practical example with an explanation here:

1.

CODE RUN WITHOUT VOLATILE USE

public class VisibilityDemonstration {

private static int sCount = 0;

public static void main(String[] args) {
    new Consumer().start();
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        return;
    }
    new Producer().start();
}

static class Consumer extends Thread {
    @Override
    public void run() {
        int localValue = -1;
        while (true) {
            if (localValue != sCount) {
                System.out.println("Consumer: detected count change " + sCount);
                localValue = sCount;
            }
            if (sCount >= 5) {
                break;
            }
        }
        System.out.println("Consumer: terminating");
    }
}

static class Producer extends Thread {
    @Override
    public void run() {
        while (sCount < 5) {
            int localValue = sCount;
            localValue++;
            System.out.println("Producer: incrementing count to " + localValue);
            sCount = localValue;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                return;
            }
        }
        System.out.println("Producer: terminating");
    }
}
}

In the above code, there are two threads - Producer and Consumer.

The producer thread iterates over the loop 5 times (with a sleep of 1000 milliSecond or 1 Sec) in between. In every iteration, the producer thread increases the value of sCount variable by 1. So, the producer changes the value of sCount from 0 to 5 in all iterations

The consumer thread is in a constant loop and print whenever the value of sCount changes until the value reaches 5 where it ends.

Both the loops are started at the same time. So both the producer and consumer should print the value of sCount 5 times.

OUTPUT

Consumer: detected count change 0
Producer: incrementing count to 1
Producer: incrementing count to 2
Producer: incrementing count to 3
Producer: incrementing count to 4
Producer: incrementing count to 5
Producer: terminating

ANALYSIS

In the above program, when the producer thread updates the value of sCount, it does update the value of the variable in the main memory(memory from where every thread is going to initially read the value of variable). But the consumer thread reads the value of sCount only the first time from this main memory and then caches the value of that variable inside its own memory. So, even if the value of original sCount in main memory has been updated by the producer thread, the consumer thread is reading from its cached value which is not updated. This is called VISIBILITY PROBLEM .

2.

CODE RUN WITH VOLATILE USE

In the above code, replace the line of code where sCount is declared by the following :

private volatile  static int sCount = 0;

OUTPUT

Consumer: detected count change 0
Producer: incrementing count to 1
Consumer: detected count change 1
Producer: incrementing count to 2
Consumer: detected count change 2
Producer: incrementing count to 3
Consumer: detected count change 3
Producer: incrementing count to 4
Consumer: detected count change 4
Producer: incrementing count to 5
Consumer: detected count change 5
Consumer: terminating
Producer: terminating

ANALYSIS

When we declare a variable volatile, it means that all reads and all writes to this variable or from this variable will go directly into the main memory. The values of these variables will never be cached.

As the value of the sCount variable is never cached by any thread, the consumer always reads the original value of sCount from the main memory(where it is being updated by producer thread). So, In this case the output is correct where both the threads prints the different values of sCount 5 times.

In this way, the volatile keyword solves the VISIBILITY PROBLEM .


Interestingly, the consumer doesn't cache the value when you print it out before the if statement. Weird
Its a great example!
I understood the point that without volatile keyword in the consumer thread the sCount value is read once and stored locally, and the same value is read throughout the life of the consumer thread. However, we do read the same sCount variable in Producer thread in the while() loop check and how does that the producer thread reads the updated value and not cached value?
M
MB.

Yes, I use it quite a lot - it can be very useful for multi-threaded code. The article you pointed to is a good one. Though there are two important things to bear in mind:

You should only use volatile if you completely understand what it does and how it differs to synchronized. In many situations volatile appears, on the surface, to be a simpler more performant alternative to synchronized, when often a better understanding of volatile would make clear that synchronized is the only option that would work. volatile doesn't actually work in a lot of older JVMs, although synchronized does. I remember seeing a document that referenced the various levels of support in different JVMs but unfortunately I can't find it now. Definitely look into it if you're using Java pre 1.5 or if you don't have control over the JVMs that your program will be running on.


t
tstuber

Every thread accessing a volatile field will read its current value before continuing, instead of (potentially) using a cached value.

Only member variable can be volatile or transient.


d
dgvid

Absolutely, yes. (And not just in Java, but also in C#.) There are times when you need to get or set a value that is guaranteed to be an atomic operation on your given platform, an int or boolean, for example, but do not require the overhead of thread locking. The volatile keyword allows you to ensure that when you read the value that you get the current value and not a cached value that was just made obsolete by a write on another thread.


M
Mohan

There are two different uses of volatile keyword.

Prevents JVM from reading values from register (assume as cache), and forces its value to be read from memory. Reduces the risk of memory in-consistency errors.

Prevents JVM from reading values in register, and forces its value to be read from memory.

A busy flag is used to prevent a thread from continuing while the device is busy and the flag is not protected by a lock:

while (busy) {
    /* do something else */
}

The testing thread will continue when another thread turns off the busy flag:

busy = 0;

However, since busy is accessed frequently in the testing thread, the JVM may optimize the test by placing the value of busy in a register, then test the contents of the register without reading the value of busy in memory before every test. The testing thread would never see busy change and the other thread would only change the value of busy in memory, resulting in deadlock. Declaring the busy flag as volatile forces its value to be read before each test.

Reduces the risk of memory consistency errors.

Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a "happens-before" relationship with subsequent reads of that same variable. This means that changes to a volatile variable are always visible to other threads.

The technique of reading, writing without memory consistency errors is called atomic action.

An atomic action is one that effectively happens all at once. An atomic action cannot stop in the middle: it either happens completely, or it doesn't happen at all. No side effects of an atomic action are visible until the action is complete.

Below are actions you can specify that are atomic:

Reads and writes are atomic for reference variables and for most primitive variables (all types except long and double).

Reads and writes are atomic for all variables declared volatile (including long and double variables).

Cheers!


s
sankar banerjee

Volatile does following.

1> Read and write of volatile variables by different threads are always from memory, not from thread's own cache or cpu register. So each thread always deals with the latest value. 2> When 2 different threads work with same instance or static variables in heap, one may see other's actions as out of order. See jeremy manson's blog on this. But volatile helps here.

Following fully running code shows how a number of threads can execute in predefined order and print outputs without using synchronized keyword.

thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3

To achieve this we may use the following full fledged running code.

public class Solution {
    static volatile int counter = 0;
    static int print = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }
    static class MyRunnable implements Runnable {
        final int thID;
        final int total;
        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                if (thID == counter) {
                    System.out.println("thread " + thID + " prints " + print);
                    print++;
                    if (print == total)
                        print = 0;
                    counter++;
                    if (counter == total)
                        counter = 0;
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }
    }
}

The following github link has a readme, which gives proper explanation. https://github.com/sankar4git/volatile_thread_ordering


C
Community

From oracle documentation page, the need for volatile variable arises to fix memory consistency issues:

Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable.

This means that changes to a volatile variable are always visible to other threads. It also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change.

As explained in Peter Parker answer, in absence of volatile modifier, each thread's stack may have their own copy of variable. By making the variable as volatile, memory consistency issues have been fixed.

Have a look at jenkov tutorial page for better understanding.

Have a look at related SE question for some more details on volatile & use cases to use volatile:

Difference between volatile and synchronized in Java

One practical use case:

You have many threads, which need to print current time in a particular format for example : java.text.SimpleDateFormat("HH-mm-ss"). Yon can have one class, which converts current time into SimpleDateFormat and updated the variable for every one second. All other threads can simply use this volatile variable to print current time in log files.


N
Neha Vari

Volatile Variables are light-weight synchronization. When visibility of latest data among all threads is requirement and atomicity can be compromised , in such situations Volatile Variables must be preferred. Read on volatile variables always return most recent write done by any thread since they are neither cached in registers nor in caches where other processors can not see. Volatile is Lock-Free. I use volatile, when scenario meets criteria as mentioned above.


N
Niyaz Ahamad

volatile variable is basically used for instant update (flush) in main shared cache line once it updated, so that changes reflected to all worker threads immediately.


J
Java Main

The volatile key when used with a variable, will make sure that threads reading this variable will see the same value . Now if you have multiple threads reading and writing to a variable, making the variable volatile will not be enough and data will be corrupted . Image threads have read the same value but each one has done some chages (say incremented a counter) , when writing back to the memory, data integrity is violated . That is why it is necessary to make the varible synchronized (diffrent ways are possible)

If the changes are done by 1 thread and the others need just to read this value, the volatile will be suitable.


m
manikanta

Below is a very simple code to demonstrate the requirement of volatile for variable which is used to control the Thread execution from other thread (this is one scenario where volatile is required).

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

When volatile is not used: you'll never see 'Stopped on: xxx' message even after 'Stopping on: xxx', and the program continues to run.

Stopping on: 1895303906650500

When volatile used: you'll see the 'Stopped on: xxx' immediately.

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

Demo: https://repl.it/repls/SilverAgonizingObjectcode


To downvoter: Care to explain why downvote? If this is not true, at least I'll learn whats wrong. I've added this same comment twice, but don't know who is deleting again and again