139

I read some articles about the volatile keyword but I could not figure out its correct usage. Could you please tell me what it should be used for in C# and in Java?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Mircea
  • 3,369
  • 6
  • 27
  • 26
  • 1
    One of the problems with volatile is that it means more than one thing. It being information to the compiler not to do funky optimizations is a C legacy. It _also_ means that memory barriers should be used on access. But in most cases it just costs performance and / or confuses people. :P – AnorZaken Feb 28 '19 at 15:00
  • Related: *[Simplest and understandable example of volatile keyword in Java](https://stackoverflow.com/questions/17748078/simplest-and-understandable-example-of-volatile-keyword-in-java)* and *[Volatile vs Static in Java](https://stackoverflow.com/questions/2423622/volatile-vs-static-in-java)* – Peter Mortensen Jun 19 '23 at 14:49

8 Answers8

174

Consider this example:

int i = 5;
System.out.println(i);

The compiler may optimize this to just print 5, like this:

System.out.println(5);

However, if there is another thread which can change i, this is the wrong behaviour. If another thread changes i to be 6, the optimized version will still print 5.

The volatile keyword prevents such optimization and caching, and thus is useful when a variable can be changed by another thread.

akjoshi
  • 15,374
  • 13
  • 103
  • 121
Sjoerd
  • 74,049
  • 16
  • 131
  • 175
  • 3
    I believe the optimisation would still be valid with `i` marked as `volatile`. In Java it is all about *happens-before* relationships. – Tom Hawtin - tackline Aug 07 '10 at 14:39
  • Thanks for posting, so somehow volatile has connections with variable locking ? – Mircea Aug 07 '10 at 14:39
  • @Mircea: That is what I was told that marking something as volatile was all about: marking a field as volatile would use some internal mechanism to allow threads to see a consistent value for the given variable, but this is not mentioned in the answer above... maybe someone can confirm this or not? Thanks – npinti Aug 07 '10 at 14:56
  • 6
    @Sjoerd: I'm not sure I understand this example. If `i` is a local variable, no other thread can change it anyway. If it's a field, the compiler can't optimize the call unless it's `final`. I don't think the compiler can make optimizations based on assuming that a field "looks" `final` when it's not explicitly declared as such. – polygenelubricants Aug 07 '10 at 15:03
  • @poly: Yes, it would probably have helped if that local variable were passed by reference to a thread. – Steven Sudit Aug 07 '10 at 16:03
  • 2
    C# and java are not C++. This is not correct. It does not prevent caching and it does not prevent optimization. It is about read-acquire, and store-release semantics, which are required on weakly ordered memory architectures. It is about speculative execution. – doug65536 Oct 07 '16 at 02:28
104

For both C# and Java, "volatile" tells the compiler that the value of a variable must never be cached as its value may change outside of the scope of the program itself. The compiler will then avoid any optimisations that may result in problems if the variable changes "outside of its control".

Will A
  • 24,780
  • 5
  • 50
  • 61
45

Reads of volatile fields have acquire semantics. This means that it is guaranteed that the memory read from the volatile variable will occur before any following memory reads. It blocks the compiler from doing the reordering, and if the hardware requires it (weakly ordered CPU), it will use a special instruction to make the hardware flush any reads that occur after the volatile read but were speculatively started early, or the CPU could prevent them from being issued early in the first place, by preventing any speculative load from occurring between the issue of the load acquire and its retirement.

Writes of volatile fields have release semantics. This means that it is guaranteed that any memory writes to the volatile variable are guaranteed to be delayed until all previous memory writes are visible to other processors.

Consider the following example:

something.foo = new Thing();

If foo is a member variable in a class, and other CPUs have access to the object instance referred to by something, they might see the value foo change before the memory writes in the Thing constructor are globally visible! This is what "weakly ordered memory" means. This could occur even if the compiler has all of the stores in the constructor before the store to foo. If foo is volatile then the store to foo will have release semantics, and the hardware guarantees that all of the writes before the write to foo are visible to other processors before allowing the write to foo to occur.

How is it possible for the writes to foo to be reordered so badly? If the cache line holding foo is in the cache, and the stores in the constructor missed the cache, then it is possible for the store to complete much sooner than the writes to the cache misses.

The (awful) Itanium architecture from Intel had weakly ordered memory. The processor used in the original XBox 360 had weakly ordered memory. Many ARM processors, including the very popular ARMv7-A have weakly ordered memory.

Developers often don't see these data races because things like locks will do a full memory barrier, essentially the same thing as acquire and release semantics at the same time. No loads inside the lock can be speculatively executed before the lock is acquired, they are delayed until the lock is acquired. No stores can be delayed across a lock release, the instruction that releases the lock is delayed until all of the writes done inside the lock are globally visible.

A more complete example is the "Double-checked locking" pattern. The purpose of this pattern is to avoid having to always acquire a lock in order to lazy initialize an object.

Snagged from Wikipedia:

public class MySingleton {
    private static object myLock = new object();
    private static volatile MySingleton mySingleton = null;

    private MySingleton() {
    }

    public static MySingleton GetInstance() {
        if (mySingleton == null) { // 1st check
            lock (myLock) {
                if (mySingleton == null) { // 2nd (double) check
                    mySingleton = new MySingleton();
                    // Write-release semantics are implicitly handled by marking
                    // mySingleton with 'volatile', which inserts the necessary memory
                    // barriers between the constructor call and the write to mySingleton.
                    // The barriers created by the lock are not sufficient because
                    // the object is made visible before the lock is released.
                }
            }
        }
        // The barriers created by the lock are not sufficient because not all threads
        // will acquire the lock. A fence for read-acquire semantics is needed between
        // the test of mySingleton (above) and the use of its contents. This fence
        // is automatically inserted because mySingleton is marked as 'volatile'.
        return mySingleton;
    }
}

In this example, the stores in the MySingleton constructor might not be visible to other processors before the store to mySingleton. If that happens, the other threads that peek at mySingleton will not acquire a lock and they will not necessarily pick up the writes to the constructor.

volatile never prevents caching. What it does is guarantee the order in which other processors "see" writes. A store release will delay a store until all pending writes are complete and a bus cycle has been issued telling other processors to discard/writeback their cache line if they happen to have the relevant lines cached. A load acquire will flush any speculated reads, ensuring that they won't be stale values from the past.

sigod
  • 3,514
  • 2
  • 21
  • 44
doug65536
  • 6,562
  • 3
  • 43
  • 53
  • Good explanation. Also good double-check locking example. However, I'm still unsure about when to use as I'm worried about the caching aspects. If I write a queue implementation where only 1 thread will be writing and only 1 thread will be reading, can I get by without locks and just mark my head and tail "pointers" as volatile? I want to ensure that both the reader and writer see the most up to date values. –  Nov 27 '16 at 23:50
  • Both `head` and `tail` need to be volatile to prevent the producer from assuming `tail` won't change, and to prevent the consumer from assuming `head` won't change. Also, `head` must be volatile to ensure that the queue data writes are globally visible before the store to `head` is globally visible. – doug65536 Nov 28 '16 at 22:34
  • +1, Terms like latest / "most updated" unfortunately imply a concept of the singular correct value. In reality two competitors can cross a finish line at the *exact same time* - on a cpu two cores can request a write at the *exact same time*. After all, cores don't take turns doing work - that would make multi-core pointless. Good multi-thread thinking / design shouldn't focus on trying to force low-level "latestness" - inherently fake since a lock just force cores to *arbitrarily* select one speaker at a time w/o fairness - but rather try to design away the need for such an unnatural concept. – AnorZaken May 05 '20 at 15:57
39

To understand what volatile does to a variable, it's important to understand what happens when the variable is not volatile.

  • Variable is Non-volatile

When two threads A & B are accessing a non-volatile variable, each thread will maintain a local copy of the variable in it's local cache. Any changes done by thread A in it's local cache won't be visible to the thread B.

  • Variable is volatile

When variables are declared volatile it essentially means that threads should not cache such a variable or in other words threads should not trust the values of these variables unless they are directly read from the main memory.

So, when to make a variable volatile?

When you have a variable which can be accessed by many threads and you want every thread to get the latest updated value of that variable even if the value is updated by any other thread/process/outside of the program.

Saurabh Patil
  • 4,170
  • 4
  • 32
  • 33
  • 4
    Wrong. It has nothing to do with "preventing caching". It is about reordering, by the compiler, OR the CPU hardware through speculative execution. – doug65536 Oct 07 '16 at 02:52
  • 3
    I don't think this is correct at all. If it was correct then multithreaded code would require `volatile` all the time. – tymtam Mar 31 '21 at 07:41
35

The volatile keyword has different meanings in both Java and C#.

Java

From the Java Language Spec :

A field may be declared volatile, in which case the Java memory model ensures that all threads see a consistent value for the variable.

C#

From the C# Reference (retrieved 2021-03-31):

The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. The compiler, the runtime system, and even hardware may rearrange reads and writes to memory locations for performance reasons. Fields that are declared volatile are not subject to these optimizations. (...)

tymtam
  • 31,798
  • 8
  • 86
  • 126
krock
  • 28,904
  • 13
  • 79
  • 85
  • Thank you very much for posting, as i understood in Java it acts like locking that variable in a thread context, and in C# if used the value of variable can be changed not only from program , external factors such as OS can modify its value (no locking implied)... Please let me know if i understood right those differences... – Mircea Aug 07 '10 at 14:58
  • @Mircea in Java there is no locking involved, it just ensures that the most up to date value of the volatile variable will be used. – krock Aug 07 '10 at 15:11
  • Does Java promise some sort of memory barrier, or is it like C++ and C# in only promising not to optimize the reference away? – Steven Sudit Aug 07 '10 at 16:04
  • The memory barrier is an implementation detail. What Java actually promises is that all reads will see the value written by the most recent write. – Stephen C Sep 24 '16 at 07:18
  • 1
    @StevenSudit Yes, if the hardware requires a barrier or load/acquire or store/release then it will use those instructions. See my answer. – doug65536 Oct 07 '16 at 02:53
9

In Java, "volatile" is used to tell the JVM that the variable may be used by multiple threads at the same time, so certain common optimizations cannot be applied.

Notably the situation where the two threads accessing the same variable are running on separate CPU's in the same machine. It is very common for CPU's to cache aggressively the data it holds because memory access is very much slower than cache access. This means that if the data is updated in CPU1 it must immediately go through all caches and to main memory instead of when the cache decides to clear itself, so that CPU2 can see the updated value (again by disregarding all caches on the way).

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
0

When you are reading data that is non-volatile, the executing thread may or may not always get the updated value. But if the object is volatile, the thread always gets the most up-to-date value.

Subhash Saini
  • 254
  • 4
  • 5
-2

Volatile is solving concurrency problem. To make that value in sync. This keyword is mostly use in a threading. When multiple thread updating same variable.

  • 1
    I don't think it "solves" the problem. It's a tool that help in some circumstance. Don't rely on volatile for situations where a lock is needed, as in a race condition. – Scratte Apr 26 '20 at 02:24