170

I read somewhere below line.

Java volatile keyword doesn't means atomic, its common misconception that after declaring volatile, ++ operation will be atomic, to make the operation atomic you still need to ensure exclusive access using synchronized method or block in Java.

So what will happen if two threads attack a volatile primitive variable at same time?

Does this mean that whosoever takes lock on it, that will be setting its value first. And if in meantime, some other thread comes up and read old value while first thread was changing its value, then doesn't new thread will read its old value?

What is the difference between Atomic and volatile keyword?

AADProgramming
  • 6,077
  • 11
  • 38
  • 58
Vaibhav
  • 3,035
  • 7
  • 24
  • 27
  • 3
    What is the difference between AtomicInteger and volatile int ? – Vaibhav Nov 02 '13 at 17:09
  • atomic operations like [++](http://download.java.net/java/jdk9/docs/api/java/util/concurrent/atomic/AtomicInteger.html#incrementAndGet--). There's like 10 atomic operations there – Pacerier Sep 20 '17 at 02:45
  • 14
    **SHORT ANSWER**: `volatile` makes **ONLY ONE** atomic read **OR** write, where atomics can do few atomic operations, e.g get**And**Add – Dmytro Melnychuk Sep 17 '18 at 21:23

6 Answers6

213

The effect of the volatile keyword is approximately that each individual read or write operation on that variable is made atomically visible to all threads.

Notably, however, an operation that requires more than one read/write -- such as i++, which is equivalent to i = i + 1, which does one read and one write -- is not atomic, since another thread may write to i between the read and the write.

The Atomic classes, like AtomicInteger and AtomicReference, provide a wider variety of operations atomically, specifically including increment for AtomicInteger.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • 21
    Something to add, the `int` stored in `AtomicInteger` is `private volatile int value;` – vallentin Nov 02 '13 at 17:14
  • 13
    @Vallentin: Yes, but `AtomicInteger` uses some special utilities -- specifically including `Unsafe.compareAndSwapInt` -- to do more powerful concurrent operations safely. – Louis Wasserman Nov 02 '13 at 17:21
  • yes yes, but my point was that `volatile` was used in `AtomicInteger`. – vallentin Nov 02 '13 at 17:44
  • 2
    This is only half the truth, you are missing the very important order-of-execution problem. See my explanation below. – TwoThe Nov 02 '13 at 18:05
  • 31
    @LouisWasserman: "The effect of `volatile` keyword is ... operation on that variable is atomic." I must disagree with the truth of this assertion. Individual reads and writes to variables in Java that are not 8-bytes are always atomic. The `volatile` keyword does not make accesses to variables that may not have otherwise been atomic into accesses that are. It merely forces the processing environment to immediately flush to main memory changes that are made to variables so that those changes are visible to all threads. – scottb Nov 02 '13 at 18:10
  • 2
    @LouisWasserman primitive read/writes are always atomic, only `long` and `double` "need" `volatile` to be atomic. – Ortwin Angermeier Nov 02 '13 at 18:29
  • 9
    @ortang: Just an affirmation. I checked the JLS (s17.7). You are correct that a `volatile` declaration will make reads and writes to longs and doubles (which otherwise would -not- be atomic) into atomic accesses in addition to providing for inter-thread visibility. – scottb Nov 02 '13 at 20:28
  • 1
    LouisWasserman Considering this is the rare instance where top voted answer is wrong/misleading, can you reword your answer after better readin volatile in Java. Agree with @OrtwinAngermeier – Ajeet Ganga Aug 29 '14 at 14:19
  • volatile only increases the variable visibility, so to reduce consistency errors. It has nothing to do with atomicity. – stdout Apr 21 '16 at 07:32
  • 1
    @TwoThe, I think you meant [half the story](https://www.google.com/search?q="half+the+story"+effective+java). – Pacerier Sep 20 '17 at 02:47
  • you can also refer to this detailed explanation: https://www.ibm.com/developerworks/library/j-jvmc1/index.html – linehrr Jan 11 '18 at 21:13
  • but this article says that volatile has nothing to do with atomic. https://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming – du369 Jan 15 '18 at 23:32
119

Volatile and Atomic are two different concepts. Volatile ensures, that a certain, expected (memory) state is true across different threads, while Atomics ensure that operation on variables are performed atomically.

Take the following example of two threads in Java:

Thread A:

value = 1;
done = true;

Thread B:

if (done)
  System.out.println(value);

Starting with value = 0 and done = false the rule of threading tells us, that it is undefined whether or not Thread B will print value. Furthermore value is undefined at that point as well! To explain this you need to know a bit about Java memory management (which can be complex), in short: Threads may create local copies of variables, and the JVM can reorder code to optimize it, therefore there is no guarantee that the above code is run in exactly that order. Setting done to true and then setting value to 1 could be a possible outcome of the JIT optimizations.

volatile only ensures, that at the moment of access of such a variable, the new value will be immediately visible to all other threads and the order of execution ensures, that the code is at the state you would expect it to be. So in case of the code above, defining done as volatile will ensure that whenever Thread B checks the variable, it is either false, or true, and if it is true, then value has been set to 1 as well.

As a side-effect of volatile, the value of such a variable is set thread-wide atomically (at a very minor cost of execution speed). This is however only important on 32-bit systems that i.E. use long (64-bit) variables (or similar), in most other cases setting/reading a variable is atomic anyways. But there is an important difference between an atomic access and an atomic operation. Volatile only ensures that the access is atomically, while Atomics ensure that the operation is atomically.

Take the following example:

i = i + 1;

No matter how you define i, a different Thread reading the value just when the above line is executed might get i, or i + 1, because the operation is not atomically. If the other thread sets i to a different value, in worst case i could be set back to whatever it was before by thread A, because it was just in the middle of calculating i + 1 based on the old value, and then set i again to that old value + 1. Explanation:

Assume i = 0
Thread A reads i, calculates i+1, which is 1
Thread B sets i to 1000 and returns
Thread A now sets i to the result of the operation, which is i = 1

Atomics like AtomicInteger ensure, that such operations happen atomically. So the above issue cannot happen, i would either be 1000 or 1001 once both threads are finished.

TwoThe
  • 13,879
  • 6
  • 30
  • 54
  • 1
    In this particular case it is possible, as in from the local perspective of the Thread there is no problem in doing that. So if it is convenient for the CPU (i.E. batch-writing of memory), reordering in that way is very much possible. – TwoThe Aug 21 '17 at 07:17
  • 1
    @momomo this is exactly what [Java memory model spec](https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4) warns about, see the 1st example there – Alexander Malakhov Aug 21 '17 at 16:59
  • 1
    So, if I have an AtomicBoolean not qualified with `volatile`, it is possible for another 2 threads get different value at the same moment? – Anderson Sep 16 '19 at 07:10
  • Never mind, I have got the answer here, AtomicBoolean have been qualified with `volatile` implicitly. https://stackoverflow.com/a/42868221/2218838 – Anderson Sep 16 '19 at 07:20
  • It is not the JVM that executes code out of order, it is the CPU. See Wikipedia: https://en.wikipedia.org/wiki/Out-of-order_execution – Basil Bourque Dec 17 '19 at 00:21
103

There are two important concepts in multithreading environment:

  1. atomicity
  2. visibility

The volatile keyword eradicates visibility problems, but it does not deal with atomicity. volatile will prevent the compiler from reordering instructions which involve a write and a subsequent read of a volatile variable; e.g. k++. Here, k++ is not a single machine instruction, but three:

  1. copy the value to a register;
  2. increment the value;
  3. place it back.

So, even if you declare a variable as volatile, this will not make this operation atomic; this means another thread can see a intermediate result which is a stale or unwanted value for the other thread.

On the other hand, AtomicInteger, AtomicReference are based on the Compare and swap instruction. CAS has three operands: a memory location V on which to operate, the expected old value A, and the new value B. CAS atomically updates V to the new value B, but only if the value in V matches the expected old value A; otherwise, it does nothing. In either case, it returns the value currently in V. The compareAndSet() methods of AtomicInteger and AtomicReference take advantage of this functionality, if it is supported by the underlying processor; if it is not, then the JVM implements it via spin lock.

Wild Pottok
  • 318
  • 3
  • 8
Trying
  • 14,004
  • 9
  • 70
  • 110
59

As Trying as indicated, volatile deals only with visibility.

Consider this snippet in a concurrent environment:

boolean isStopped = false;
    :
    :

    while (!isStopped) {
        // do some kind of work
    }

The idea here is that some thread could change the value of isStopped from false to true in order to indicate to the subsequent loop that it is time to stop looping.

Intuitively, there is no problem. Logically if another thread makes isStopped equal to true, then the loop must terminate. The reality is that the loop will likely never terminate even if another thread makes isStopped equal to true.

The reason for this is not intuitive, but consider that modern processors have multiple cores and that each core has multiple registers and multiple levels of cache memory that are not accessible to other processors. In other words, values that are cached in one processor's local memory are not visisble to threads executing on a different processor. Herein lies one of the central problems with concurrency: visibility.

The Java Memory Model makes no guarantees whatsoever about when changes that are made to a variable in one thread may become visible to other threads. In order to guarantee that updates are visisble as soon as they are made, you must synchronize.

The volatile keyword is a weak form of synchronization. While it does nothing for mutual exclusion or atomicity, it does provide a guarantee that changes made to a variable in one thread will become visible to other threads as soon as it is made. Because individual reads and writes to variables that are not 8-bytes are atomic in Java, declaring variables volatile provides an easy mechanism for providing visibility in situations where there are no other atomicity or mutual exclusion requirements.

Yogesh Umesh Vaity
  • 41,009
  • 21
  • 145
  • 105
scottb
  • 9,908
  • 3
  • 40
  • 56
  • 5
    Thanks, this answer is I think a better answer for me.. So clear., I stopped a thread with a simple status value from a primitive boolean var that I wondered why it didn't stop at some point of running (sometimes it did stop)..., – Plain_Dude_Sleeping_Alone Dec 24 '15 at 22:23
  • great answer. When I was reading some articles online, I got confused when they talked about java may return value from "cache" which may not reflect newly assigned value. I don't know what cache means in that context. Now it clears. – KMC Apr 28 '22 at 11:19
  • I hear about the need to "flush CPU caches" very often. Doesn't a cache coherency protocol ensure that an updated cache line is broadcasted to all cores atomically? In this case the only place where cores can hold stale values is registers. – raiks Feb 13 '23 at 18:22
23

The volatile keyword is used:

  • to make non atomic 64-bit operations atomic: long and double. (all other, primitive accesses are already guaranteed to be atomic!)
  • to make variable updates guaranteed to be seen by other threads + visibility effects: after writing to a volatile variable, all the variables that where visible before writing that variable become visible to another thread after reading the same volatile variable (happen-before ordering).

The java.util.concurrent.atomic.* classes are, according to the java docs:

A small toolkit of classes that support lock-free thread-safe programming on single variables. In essence, the classes in this package extend the notion of volatile values, fields, and array elements to those that also provide an atomic conditional update operation of the form:

boolean compareAndSet(expectedValue, updateValue);

The atomic classes are built around the atomic compareAndSet(...) function that maps to an atomic CPU instruction. The atomic classes introduce the happen-before ordering as the volatile variables do. (with one exception: weakCompareAndSet(...)).

From the java docs:

When a thread sees an update to an atomic variable caused by a weakCompareAndSet, it does not necessarily see updates to any other variables that occurred before the weakCompareAndSet.

To your question:

Does this mean that whosoever takes lock on it, that will be setting its value first. And in if meantime, some other thread comes up and read old value while first thread was changing its value, then doesn't new thread will read its old value?

You don't lock anything, what you are describing is a typical race condition that will happen eventually if threads access shared data without proper synchronization. As already mentioned declaring a variable volatile in this case will only ensure that other threads will see the change of the variable (the value will not be cached in a register of some cache that is only seen by one thread).

What is the difference between AtomicInteger and volatile int?

AtomicInteger provides atomic operations on an int with proper synchronization (eg. incrementAndGet(), getAndAdd(...), ...), volatile int will just ensure the visibility of the int to other threads.

Ortwin Angermeier
  • 5,957
  • 2
  • 34
  • 34
  • atomic and volatile are two mutually exclusive concepts. See https://stackoverflow.com/a/19744659/632951 – Pacerier Sep 20 '17 at 02:49
  • 5
    Java Spec 17.7: `...a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write. Writes and reads of volatile long and double values are always atomic. Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.` Link: https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7 – Philip Guin Dec 10 '17 at 03:57
  • 1
    @Pacerier i agree with you in general, but there is the thing in java, that you need the volatile keyword to make 64bit values atomic. So they are not mutually exclusive anymore. – Ortwin Angermeier Dec 21 '17 at 13:15
16

So what will happen if two threads attack a volatile primitive variable at same time?

Usually each one can increment the value. However sometime, both will update the value at the same time and instead of incrementing by 2 total, both thread increment by 1 and only 1 is added.

Does this mean that whosoever takes lock on it, that will be setting its value first.

There is no lock. That is what synchronized is for.

And in if meantime, some other thread comes up and read old value while first thread was changing its value, then doesn't new thread will read its old value?

Yes,

What is the difference between Atomic and volatile keyword?

AtomicXxxx wraps a volatile so they are basically same, the difference is that it provides higher level operations such as CompareAndSwap which is used to implement increment.

AtomicXxxx also supports lazySet. This is like a volatile set, but doesn't stall the pipeline waiting for the write to complete. It can mean that if you read a value you just write you might see the old value, but you shouldn't be doing that anyway. The difference is that setting a volatile takes about 5 ns, bit lazySet takes about 0.5 ns.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130