Simplest and understandable example of volatile keyword in Java
Asked Answered
C

13

85

I'm reading about volatile keyword in Java and completely understand the theory part of it.

But, what I'm searching for is, a good case example, which shows what would happen if variable wasn't volatile and if it were.

Below code snippet doesn't work as expected (taken from here):

class Test extends Thread {

    boolean keepRunning = true;

    public void run() {
        while (keepRunning) {
        }

        System.out.println("Thread terminated.");
    }

    public static void main(String[] args) throws InterruptedException {
        Test t = new Test();
        t.start();
        Thread.sleep(1000);
        t.keepRunning = false;
        System.out.println("keepRunning set to false.");
    }
}

Ideally, if keepRunning wasn't volatile, thread should keep on running indefinitely. But, it does stop after few seconds.

I've got two basic questions:

  • Can anyone explain volatile with example? Not with theory from JLS.
  • Is volatile substitute for synchronization? Does it achieve atomicity?
Counteraccusation answered 19/7, 2013 at 14:2 Comment(6)
A past post talks of it extensively https://mcmap.net/q/15879/-java-threading-volatilePhotolithography
You are thinking backwards. Ideally, if keepRunning wasn't volatile, thread should keep on running indefinitely. Actually, it is the opposite: adding volatile guarantees that the change to the field will be visible. Without the keyword, simply there are no guarantees at all, anything can happen; you cannot state that thread should keep on running [...].Mceachern
Here's the thing: memory visibility bugs are by their nature hard (impossible?) to demonstrate by a simple example that will fail every time. Assuming you've got a multi-core machine, your example will probably fail at least a couple times if you run it a lot (say, 1000 runs). If you've got a big program -- such that the whole program and its objects don't fit on a CPU cache, for instance -- then that increases the probability of seeing a bug. Basically, concurrency bugs are such that if the theory says it can break, it probably will, but only once every few months, and probably in production.Nightrider
There is good example already listed stackoverflow.com/questions/5816790/…Christian
Here is an example with a write up vanillajava.blogspot.co.uk/2012/01/…Hematology
@PeterLawrey - that post is full of misleading speculations and false info, RequiresVolatileMain can NOT show the necessity of volatile. If each thread cached its own copy of "value" we'd always seen this: Sets true: value=true target=true and Sets false: value=false target=false, BUT: tons of circumstances can lead to same output... Tried to put same on blogspot, but "Comments are restricted to team members"Albrecht
U
52

Volatile --> Guarantees visibility and NOT atomicity

Synchronization (Locking) --> Guarantees visibility and atomicity (if done properly)

Volatile is not a substitute for synchronization

Use volatile only when you are updating the reference and not performing some other operations on it.

Example:

volatile int i = 0;

public void incrementI(){
   i++;
}

will not be thread safe without use of synchronization or AtomicInteger as incrementing is an compound operation.

Why program does not run indefinitely?

Well that depends on various circumstances. In most cases JVM is smart enough to flush the contents.

Correct use of volatile discusses various possible uses of volatile. Using volatile correctly is tricky, I would say "When in doubt, Leave it out", use synchronized block instead.

Also:

synchronized block can be used in place of volatile but the inverse is not true.

Uitlander answered 19/7, 2013 at 14:7 Comment(3)
This is wrong. volatile guarantees atomic nature. Oracle documentation clearly specifies this. See docs.oracle.com/javase/tutorial/essential/concurrency/….Disharoon
In Java when we have multiple threads, each thread have its own stack (a memory space) and init each thread has its own copy of variables it can access . If volatile key word is not there to decorate int i ,each thread may use it in their executions. When declared with volatile, each thread has to read/write value of i from/to direcltly main memory , not to/from local copies. So in each threads perspective, operations to/from variable i is atomic.Disharoon
atomicity part of the answer is confusing. Synchronization gives you mutual exclusive access and visibility. volatile gives only visibility. Also volatile makes read/write for long and double atomic (Synchronization does it too by its mutual exclusive nature).Vaginal
R
28

For your particular example: if not declared volatile the server JVM could hoist the keepRunning variable out of the loop because it is not modified in the loop (turning it into an infinite loop), but the client JVM would not. That is why you see different results.

General explanation about volatile variables follows:

When a field is declared volatile, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread.

The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable.

The most common use for volatile variables is as a completion, interruption, or status flag:

  volatile boolean flag;
  while (!flag)  {
     // do something untill flag is true
  }

Volatile variables can be used for other kinds of state information, but more care is required when attempting this. For example, the semantics of volatile are not strong enough to make the increment operation (count++) atomic, unless you can guarantee that the variable is written only from a single thread.

Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.

You can use volatile variables only when all the following criteria are met:

  • Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value;
  • The variable does not participate in invariants with other state variables; and
  • Locking is not required for any other reason while the variable is being accessed.

Debugging tip: be sure to always specify the -server JVM command line switch when invoking the JVM, even for development and testing. The server JVM performs more optimization than the client JVM, such as hoisting variables out of a loop that are not modified in the loop; code that might appear to work in the development environment (client JVM) can break in the deployment environment (server JVM).

This is an excerpt from "Java Concurrency in Practice", the best book you can find on this subject.

Rossiter answered 19/7, 2013 at 14:24 Comment(0)
M
20

I have modified your example slightly. Now use the example with keepRunning as volatile and non volatile member :

class TestVolatile extends Thread{
    //volatile
    boolean keepRunning = true;

    public void run() {
        long count=0;
        while (keepRunning) {
            count++;
        }

        System.out.println("Thread terminated." + count);
    }

    public static void main(String[] args) throws InterruptedException {
        TestVolatile t = new TestVolatile();
        t.start();
        Thread.sleep(1000);
        System.out.println("after sleeping in main");
        t.keepRunning = false;
        t.join();
        System.out.println("keepRunning set to " + t.keepRunning);
    }
}
Morgue answered 5/1, 2014 at 10:2 Comment(4)
Great example. This worked perfectly at me. without volatile on keepRunning the thread hangs forever. Once you mark keepRunning as volatile - it stops after t.keepRunning = false;Gerent
Example worked for me, been searching for working example. +1 because it helped me, and the lack of explanation did not harm and don't deserve the down vote.Implead
Hi paritosht and @John Doe, could you help explain why your code is an working example? When my machine execute the code provided in the question, with or without the volatile key word, it stops anyway.Protege
I get the same result with and withour votalite hereNanette
J
19

What is the volatile keyword? The volatile keyword prevents caching of variables.

Consider this code, first without the volatile keyword:

class MyThread extends Thread {
    private boolean running = true;   //non-volatile keyword

    public void run() {
        while (running) {
            System.out.println("hello");
        }
    }

    public void shutdown() {
        running = false;
    }
}

public class Main {

    public static void main(String[] args) {
        MyThread obj = new MyThread();
        obj.start();

        Scanner input = new Scanner(System.in);
        input.nextLine(); 
        obj.shutdown();   
    }    
}

Ideally, this program should print hello until the Return key is pressed. But on some machines it may happen that the variable running is cached and you cannot change its value from the shutdown() method which results in infinite printing of the hello text.

Thus, by using the volatile keyword, it is guaranteed that your variable will not be cached and the code will run fine on all machines.

private volatile boolean running = true;  //volatile keyword

Using the volatile keyword is a good and safer programming practice.

Jacksmelt answered 18/7, 2015 at 20:8 Comment(1)
"Using the volatile keyword is a good and safer programming practice." makes it sound like you should add it to all variables unequivocally. volatile is not good or safer if you have other means of ensuring synchronization on the data and you want caching for performance reasons. volatile is a tool that can be misused just like anything else.Monocyclic
R
7

Ideally, if keepRunning wasn't volatile, thread should keep on running indefinitely. But, it does stop after few seconds.

If you are running in a single-processor or if your system is very busy, the OS may be swapping out the threads which causes some levels of cache invalidation. Not having a volatile doesn't mean that memory will not be shared, but the JVM is trying to not synchronize memory if it can for performance reasons so the memory may not be updated.

Another thing to note is that System.out.println(...) is synchronized because the underlying PrintStream does synchronization to stop overlapping output. So you are getting memory synchronization "for free" in the main-thread. This still doesn't explain why the reading loop sees the updates at all however.

Whether the println(...) lines are in or out, your program spins for me under Java6 on a MacBook Pro with an Intel i7.

Can anyone explain volatile with example ? Not with theory from JLS.

I think your example is good. Not sure why it isn't working with all System.out.println(...) statements removed. It works for me.

Is volatile substitute for synchronization ? Does it achieve atomicity ?

In terms of memory synchronization, volatile throws up the same memory barriers as a synchronized block except that the volatile barrier is uni-directional versus bi-directional. volatile reads throw up a load-barrier while writes throw up a store-barrier. A synchronized block is a bi-directional barrier with the addition of mutex locking.

In terms of atomicity, however, the answer is "it depends". If you are reading or writing a value from a field then volatile provides proper atomicity. However, incrementing a volatile field suffers from the limitation that ++ is actually 3 operations: read, increment, write. In that case or more complex mutex cases, a full synchronized block may be necessary. AtomicInteger solves the ++ issue with a complicated test-and-set spin-loop.

Rubierubiginous answered 19/7, 2013 at 14:4 Comment(12)
I commented both SOPln statements, but it still gets stopped after few seconds .. can you show me an example which would work as expected ?Counteraccusation
Are you running on a single processor system @tm99? Because your program spins forever for me on a Macbook Pro Java6.Rubierubiginous
I m running on Win Xp 32 bit Java 6Counteraccusation
@Rubierubiginous I don't think println synchronization causes the variable to be flushed because keepRunning isn't actually accessed within the synchronization of that method.Arioso
Doesn't matter @JeffStorey. Any synchronized block (or any volatile field) causes all memory to be sync'd.Rubierubiginous
"Any synchronized block (or any volatile field) causes all memory to be sync'd" -- are you sure? Would you provide JLS reference to it? As far as I remember, the only guarantee is that the modifications to the memory performed before releasing a lock L1 are visible to threads after they acquire the same lock L1; with volatiles, all memory modifications before a volatile write to F1 are visible to a thread after a volatile read of the same field F1, which is very different from saying that all* memory is sync'd. It is not as simple as any thread running a synchronized block.Mceachern
You are confused with "synchronization order". From "Java concurrency In Practice": When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable.Rubierubiginous
Yes, that's exactly what I stated above. But your previous comment says something quite different. That's why I asked for any JLS reference supporting what you said (ie, that any synchronized block or any volatile field causes all memory to be sync'd).Mceachern
When any memory barrier is crossed (with synchronized or volatile) there is a "happens before" relationship for all memory. There is no guarantees about the order of the locks and synchronization unless you lock on the same monitor which is what you are referred to @BrunoReis. But if the println(...) completes, you are guaranteed that the keepRunning field is updated.Rubierubiginous
@Gray, the thing is: suppose thread T1 acquires a lock L1 and modifies the memory, then releases the lock L1. Now, thread T2 doesn't acquire the lock L1; it may acquire a different lock L2, or no locks at all. In this circumstance, there is no guarantee (or, I'd really appreciate that you could show me any references to the JLS stating the opposite, since that's what you seem to be saying) that T2 will see the modifications performed by T1.Mceachern
If println(...) on main() completes (which we are guaranteed that will eventually happen), that only means that the lock on System.out will have been acquired and released by the main thread. However, it says nothing about the visibility of the memory by the secondary thread: it did not acquire that same lock nor did it perform a volatile read on a field that has been written to by the main thread. Therefore, no guarantees that the secondary thread will see the changes to keepRunning, which would be the case if the loop contained a System.out.println(), which is not the case.Mceachern
let us continue this discussion in chatRubierubiginous
P
7

Variable Volatile: Volatile Keyword is applicable to variables. volatile keyword in Java guarantees that value of the volatile variable will always be read from main memory and not from Thread's local cache.

Access_Modifier volatile DataType Variable_Name;

Volatile Field: An indication to the VM that multiple threads may try to access/update the field's value at the same time. To a special kind of instance variables which has to shared among all the threads with Modified value. Similar to Static(Class) variable, Only one copy of volatile value is cached in main memory, So that before doing any ALU Operations each thread has to read the updated value from Main memory after ALU operation it has to write to main memory direclty. (A write to a volatile variable v synchronizes-with all subsequent reads of v by any thread) This means that changes to a volatile variable are always visible to other threads.

enter image description here

Here to a nonvoltaile variable if Thread t1 changes the value in t1's cache, Thread t2 can't access the changed value untill t1 writes, t2 read from main memory for the most recent modified value, which may lead to Data-Inconsistancy.

volatile cannot be cached - assembler

    +--------------+--------+-------------------------------------+
    |  Flag Name   |  Value | Interpretation                      |
    +--------------+--------+-------------------------------------+
    | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
    +--------------+--------+-------------------------------------+
    |ACC_TRANSIENT | 0x0080 | Declared transient; not written or  |
    |              |        | read by a persistent object manager.|
    +--------------+--------+-------------------------------------+

Shared Variables: Memory that can be shared between threads is called shared memory or heap memory. All instance fields, static fields, and array elements are stored in heap memory.

Synchronization: synchronized is applicable to methods, blocks. allows to execute only 1-thread at a time on object. If t1 takes control, then remaining threads has to wait untill it release the control.

Example:

public class VolatileTest implements Runnable {

    private static final int MegaBytes = 10241024;

    private static final Object counterLock = new Object();
    private static int counter = 0;
    private static volatile int counter1 = 0;

    private volatile int counter2 = 0;
    private int counter3 = 0;

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            concurrentMethodWrong();
        }

    }

    void addInstanceVolatile() {
        synchronized (counterLock) {
            counter2 = counter2 + 1;
            System.out.println( Thread.currentThread().getName() +"\t\t « InstanceVolatile :: "+ counter2);
        }
    }

    public void concurrentMethodWrong() {
        counter = counter + 1;
        System.out.println( Thread.currentThread().getName() +" « Static :: "+ counter);
        sleepThread( 1/4 );

        counter1 = counter1 + 1;
        System.out.println( Thread.currentThread().getName() +"\t « StaticVolatile :: "+ counter1);
        sleepThread( 1/4 );

        addInstanceVolatile();
        sleepThread( 1/4 );

        counter3 = counter3 + 1;
        sleepThread( 1/4 );
        System.out.println( Thread.currentThread().getName() +"\t\t\t\t\t « Instance :: "+ counter3);
    }
    public static void main(String[] args) throws InterruptedException {
        Runtime runtime = Runtime.getRuntime();

        int availableProcessors = runtime.availableProcessors();
        System.out.println("availableProcessors :: "+availableProcessors);
        System.out.println("MAX JVM will attempt to use : "+ runtime.maxMemory() / MegaBytes );
        System.out.println("JVM totalMemory also equals to initial heap size of JVM : "+ runtime.totalMemory() / MegaBytes );
        System.out.println("Returns the amount of free memory in the JVM : "+ untime.freeMemory() / MegaBytes );
        System.out.println(" ===== ----- ===== ");

        VolatileTest volatileTest = new VolatileTest();
        Thread t1 = new Thread( volatileTest );
        t1.start();

        Thread t2 = new Thread( volatileTest );
        t2.start();

        Thread t3 = new Thread( volatileTest );
        t3.start();

        Thread t4 = new Thread( volatileTest );
        t4.start();

        Thread.sleep( 10 );;

        Thread optimizeation = new Thread() {
            @Override public void run() {
                System.out.println("Thread Start.");

                Integer appendingVal = volatileTest.counter2 + volatileTest.counter2 + volatileTest.counter2;

                System.out.println("End of Thread." + appendingVal);
            }
        };
        optimizeation.start();
    }

    public void sleepThread( long sec ) {
        try {
            Thread.sleep( sec * 1000 );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Static[Class Field] vs Volatile[Instance Field] - Both are not cached by threads

  • Static fields are common to all threads and get stored in Method Area. Static with volatile no use. Static field cant be serialized.

  • Volatile mainly used with instance variable which get stored in heap area. The main use of volatile is to maintain updated value over all the Threads. instance volatile field can be Serialized.

@see

Pianette answered 7/12, 2017 at 13:2 Comment(0)
A
3

When a variable is volatile, it is guaranteeing that it will not be cached and that different threads will see the updated value. However, not marking it volatile does not guarantee the opposite. volatile was one of those things that was broken in the JVM for a long time and still not always well understood.

Arioso answered 19/7, 2013 at 14:5 Comment(2)
In a modern multi-processor @Jeff, your last comment is somewhat wrong/misleading. The JVM is really smart about not flushing the value since to do so is a performance hit.Rubierubiginous
When keepRunning is set to false by main, the thread still sees the update because the JVM is smart about flushing the value. This is not guaranteed though (see comment from @Rubierubiginous above).Arioso
D
2

volatile is not going to necessarily create giant changes, depending on the JVM and compiler. However, for many (edge) cases, it can be the difference between optimization causing a variable's changes to fail to be noticed as opposed to them being correctly written.

Basically, an optimizer may choose to put non-volatile variables on registers or on the stack. If another thread changes them in the heap or the classes' primitives, the other thread will keep looking for it on the stack, and it'll be stale.

volatile ensures such optimizations don't happen and all reads and writes are directly to the heap or another place where all threads will see it.

Dotted answered 19/7, 2013 at 14:5 Comment(0)
S
2

Lot's of great examples, but I just want to add that there are a number of scenarios where volatile is required so there is no one concrete example to rule them a.

  1. You can use volatile to force all threads to get latest value of the variable from main memory.
  2. You can use synchronization to guard critical data
  3. You can use Lock API
  4. You can use Atomic variables

Check it out for more Java volatile examples.

Shun answered 5/8, 2019 at 20:57 Comment(0)
S
2
public class VolatileDemo {
    static class Processor {
        //without volatile program keeps running on my platform
        private boolean flag = false;

        public void setFlag() {
            System.out.println("setting flag true");
            this.flag = true;
        }

        public void process() {
            while(!flag) {
                int x = 5;
                // using sleep or sout will end the program without volatile.
                // Probably these operations, cause thread to be rescheduled, read from memory. Thus read new flag value and end.
            }

            System.out.println("Ending");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Processor processor = new Processor();
        Thread t1 = new Thread(processor::process);

        t1.start();

        Thread.sleep(2000);
        processor.setFlag();

    }
}
Schumann answered 7/5, 2021 at 15:39 Comment(0)
T
1

Please find the solution below,

The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory". The volatile force the thread to update the original variable for each time.

public class VolatileDemo {

    private static volatile int MY_INT = 0;

    public static void main(String[] args) {

        ChangeMaker changeMaker = new ChangeMaker();
        changeMaker.start();

        ChangeListener changeListener = new ChangeListener();
        changeListener.start();

    }

    static class ChangeMaker extends Thread {

        @Override
        public void run() {
            while (MY_INT < 5){
                System.out.println("Incrementing MY_INT "+ ++MY_INT);
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException exception) {
                    exception.printStackTrace();
                }
            }
        }
    }

    static class ChangeListener extends Thread {

        int local_value = MY_INT;

        @Override
        public void run() {
            while ( MY_INT < 5){
                if( local_value!= MY_INT){
                    System.out.println("Got Change for MY_INT "+ MY_INT);
                    local_value = MY_INT;
                }
            }
        }
    }

}

Please refer this link http://java.dzone.com/articles/java-volatile-keyword-0 to get more clarity in it.

Towel answered 28/10, 2014 at 13:43 Comment(2)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.Landre
Yeah, You are absolutely correct. I will add it. Thanks for your valuable comment.Towel
F
1

The volatile keyword tells the JVM that it may be modified by another thread. Each thread has its own stack, and so its own copy of variables it can access. When a thread is created, it copies the value of all accessible variables in its own memory.

public class VolatileTest {
    private static final Logger LOGGER = MyLoggerFactory.getSimplestLogger();

    private static volatile int MY_INT = 0;

    public static void main(String[] args) {
        new ChangeListener().start();
        new ChangeMaker().start();
    }

    static class ChangeListener extends Thread {
        @Override
        public void run() {
            int local_value = MY_INT;
            while ( local_value < 5){
                if( local_value!= MY_INT){
                    LOGGER.log(Level.INFO,"Got Change for MY_INT : {0}", MY_INT);
                     local_value= MY_INT;
                }
            }
        }
    }

    static class ChangeMaker extends Thread{
        @Override
        public void run() {

            int local_value = MY_INT;
            while (MY_INT <5){
                LOGGER.log(Level.INFO, "Incrementing MY_INT to {0}", local_value+1);
                MY_INT = ++local_value;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) { e.printStackTrace(); }
            }
        }
    }
}

try out this example with and without volatile.

Florez answered 8/2, 2019 at 6:31 Comment(0)
Y
0

Objects that are declared as volatile are usually used to communicate state information among threads,To ensure CPU caches are updated, that is, kept in sync, in the presence of volatile fields, a CPU instruction, a memory barrier, often called a membar or fence, is emitted to update CPU caches with a change in a volatile field’s value.

The volatile modifier tells the compiler that the variable modified by volatile can be changed unexpectedly by other parts of your program.

The volatile variable must be used in Thread Context only. see the example here

Yearly answered 28/10, 2013 at 19:49 Comment(1)
Caches are always kept in sync on modern CPUs independent of volatile or not.Komsomol

© 2022 - 2024 — McMap. All rights reserved.