multithreading - Volatile variable in Java

18
2014-04
  • denniss

    So I am reading this book titled "Java Concurrency in Practice" and I am stuck on this one explanation which I cannot seem to comprehend without an example. This is the quote

    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.

    Can someone give me a counterexample of why "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"?

    I am confused why all other non-volatile variables do not become visible to B before reading the volatile variable?

  • Answers
  • bkail

    Thread B may have a CPU-local cache of those variables. A read of a volatile variable ensures that any intermediate cache flush from a previous write to the volatile is observed.

    For an example, read the following link, which concludes with "Fixing Double-Checked Locking using Volatile":

    http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

  • reevesy

    Declaring a volatile Java variable means:

    • The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory".
    • Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.

    Just for your reference, When is volatile needed ?

    When multiple threads using the same variable, each thread will have its own copy of the local cache for that variable. So, when it's updating the value, it is actually updated in the local cache not in the main variable memory. The other thread which is using the same variable doesn't know anything about the values changed by the another thread. To avoid this problem, if you declare a variable as volatile, then it will not be stored in the local cache. Whenever thread are updating the values, it is updated to the main memory. So, other threads can access the updated value.

    From JLS §17.4.7 Well-Formed Executions

    We only consider well-formed executions. An execution E = < P, A, po, so, W, V, sw, hb > is well formed if the following conditions are true:

    1. Each read sees a write to the same variable in the execution. All reads and writes of volatile variables are volatile actions. For all reads r in A, we have W(r) in A and W(r).v = r.v. The variable r.v is volatile if and only if r is a volatile read, and the variable w.v is volatile if and only if w is a volatile write.

    2. Happens-before order is a partial order. Happens-before order is given by the transitive closure of synchronizes-with edges and program order. It must be a valid partial order: reflexive, transitive and antisymmetric.

    3. The execution obeys intra-thread consistency. For each thread t, the actions performed by t in A are the same as would be generated by that thread in program-order in isolation, with each write wwriting the value V(w), given that each read r sees the value V(W(r)). Values seen by each read are determined by the memory model. The program order given must reflect the program order in which the actions would be performed according to the intra-thread semantics of P.

    4. The execution is happens-before consistent (§17.4.6).

    5. The execution obeys synchronization-order consistency. For all volatile reads r in A, it is not the case that either so(r, W(r)) or that there exists a write win A such that w.v = r.v and so(W(r), w) and so(w, r).

    Useful Link : What do we really know about non-blocking concurrency in Java?

  • Vineet Reynolds

    If a variable is non-volatile, then the compiler and the CPU, may re-order instructions freely as they see fit, in order to optimize for performance.

    If the variable is now declared volatile, then the compiler no longer attempts to optimize accesses (reads and writes) to that variable. It may however continue to optimize access for other variables.

    At runtime, when a volatile variable is accessed, the JVM generates appropriate memory barrier instructions to the CPU. The memory barrier serves the same purpose - the CPU is also prevent from re-ordering instructions.

    When a volatile variable is written to (by thread A), all writes to any other variable are completed (or will atleast appear to be) and made visible to A before the write to the volatile variable; this is often due to a memory-write barrier instruction. Likewise, any reads on other variables, will be completed (or will appear to be) before the read (by thread B); this is often due to a memory-read barrier instruction. This ordering of instructions that is enforced by the barrier(s), will mean that all writes visible to A, will be visible B. This however, does not mean that any re-ordering of instructions has not happened (the compiler may have performed re-ordering for other instructions); it simply means that if any writes visible to A have occurred, it would be visible to B. In simpler terms, it means that strict-program order is not maintained.

    I will point to this writeup on Memory Barriers and JVM Concurrency, if you want to understand how the JVM issues memory barrier instructions, in finer detail.

    Related questions

    1. What is a memory fence?
    2. What are some tricks that a processor does to optimize code?
  • Bohemian

    Threads are allowed to cache variable values that other threads may have since updated since they read them. The volatile keyword forces all threads to not cache values.

  • Paŭlo Ebermann

    This is simply an additional bonus the memory model gives you, if you work with volatile variables.

    Normally (i.e. in the absence of volatile variables and synchronization), the VM can make variables from one thread visible to other threads in any order it wants, or not at all. E.g. the reading thread could read some mixture of earlier versions of another threads variable assignments. This is caused by the threads being maybe run on different CPUs with their own caches, which are only sometimes copied to the "main memory", and additionally by code reordering for optimization purposes.

    If you used a volatile variable, as soon as thread B read some value X from it, the VM makes sure that anything which thread A has written before it wrote X is also visible to B. (And also everything which A got guaranteed as visible, transitively).

    Similar guarantees are given for synchronized blocks and other types of locks.


  • Related Question

    multithreading - Why aren't variables in Java volatile by default?
  • Lucky

    Possibly similar question:

    http://stackoverflow.com/questions/106591/


    Today I was debugging my game; It had a very difficult threading problem that would show up every few minutes, but was difficult to reproduce. So first I added the synchronized keyword to each of my methods. That didn't work. Then I added the volatile keyword to every field. The problem seemed to just fix itself.

    After some experimentation I found that the field responsible was a GameState object which kept track of my game's current state, which can be either playing or busy. When busy, the game ignores user input. What I had was a thread that constantly changed the state variable, while the Event thread reads the state variable. However, after one thread changes the variable, it takes several seconds for the other thread to recognize the changes, which ultimately causes the problem.

    It was fixed by making the state variable volatile.

    Why aren't variables in Java volatile by default and what's a reason not to use the volatile keyword?


  • Related Answers
  • Adam Robinson

    To make a long story short, volatile variables--be they in Java or C#--are never cached locally within the thread. This doesn't have much of an implication unless you're dealing with a multiprocessor/multicore CPU with threads executing on different cores, as they'd be looking at the same cache. When you declare a variable as volatile, all reads and writes come straight from and go straight to the actual main memory location; there's no cache involved. This has implications when it comes to optimization, and to do so unnecessarily (when most variables don't need to be volatile) would be inflicting a performance penalty (paltry as it may or may not be) for a relatively small gain.

  • Jon Skeet

    Volatiles are really only needed when you're trying to write low-level thread-safe, lock-free code. Most of your code probably shouldn't be either thread-safe or lock-free. In my experience, lock-free programming is only worth attempting after you've found that the simpler version which does do locking is incurring a significant performance hit due to the locking.

    The more pleasant alternative is to use other building blocks in java.util.concurrent, some of which are lock-free but don't mess with your head quite as much as trying to do it all yourself at a low level.

    Volatility has its own performance costs, and there's no reason why most code should incur those costs.

  • StaxMan

    While others are correct in pointing out why it would be a bad idea to default to volatile, there's another point to make: there is very likely a bug in your code. Variables seldom need to made volatile: there is always a way to properly synchronize access to variables (either by synchronized keyword, or using AtomicXxx objects from java.util.concurrency): exceptions would include JNI code manipulating these (which is not bound by synchronization directives).

    So instead of adding volatile, you may want to figure out WHY it resolved the problem. It isn't the only way to solve it, and there is probably a better way.

  • Peter Lawrey

    Personally I think fields should have been final by default and mutable only with an extra keyword, but that boat has sailed along time ago. ;)

  • David Johnstone

    Because the compiler can't optimise volatile variables.

    volatile tells the compiler that the variable can change at any time. Therefore, it can't assume that the variable won't change and optimise accordingly.

  • Chris Arguin

    Declaring variables volatile generally has a huge impact on performance. On traditional single-threaded systems, it was relativly easy to know what needed to be volatile; it was those things that accessed hardware.

    On multi-threaded it can be a little more complex, but I would generally encourage using notifications and event queues to handle passing data between theads in leau of magic variables. In Java it may not matter much; in C/C++ you would get into trouble when those variables cannot be set atomically by the underlying hardware.