61

Is a volatile int in Java thread-safe? That is, can it be safely read from and written to without locking?

hopper
  • 12,140
  • 7
  • 48
  • 50
shawn
  • 3,713
  • 6
  • 32
  • 53

6 Answers6

76

Yes, you can read from it and write to it safely - but you can't do anything compound such as incrementing it safely, as that's a read/modify/write cycle. There's also the matter of how it interacts with access to other variables.

The precise nature of volatile is frankly confusing (see the memory model section of the JLS for more details) - I would personally generally use AtomicInteger instead, as a simpler way of making sure I get it right.

heenenee
  • 18,987
  • 1
  • 49
  • 81
Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • 13
    You can increment a `volatile int` safely, but you'll need to replace `++` with a whole load `AtomicIntegerFieldUpdater`. (Not as fast, but if access is dominated by simple read/write and/or memory overhead is important, it can be useful) – Tom Hawtin - tackline Oct 18 '11 at 09:45
  • @TomHawtin-tackline: Thanks for the detail :) – Jon Skeet Oct 18 '11 at 10:14
  • 2
    For a fuller illustration of the ++ problem, I found http://jeremymanson.blogspot.com/2007/08/volatile-does-not-mean-atomic.html nice and clear. – Holly Cummins May 22 '13 at 16:09
  • 1
    Compound operation (++) on volatiles are thread-safe when only 1 thread performs that op. Another thread can then safely read the value. – Sumit Nigam Mar 03 '15 at 14:33
  • 5
    Not to nitpick, but everything is thread-safe when only 1 thread performs it. – npace Feb 25 '16 at 15:04
  • 2
    @npace: Sumit was talking about the scenario where one thread writes while another reads. – Emily Chen May 31 '18 at 00:56
8

[...] as in being able to be safely read from and written to without locking?

Yes, a read will always result in the value of the last write, (and both reads and writes are atomic operations).

A volatile read / write introduces a so called happens-before relation in the execution.

From the Java Language Specification Chapter 17: Threads and Locks

A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.

In other words, when dealing with volatile variables you don't have to explicitly synchronize (introduce a happens-before relation) using synchronized keyword in order to ensure that the thread gets the latest value written to the variable.

As Jon Skeet points out though, the use of volatile variables are limited, and you should in general consider using classes from the java.util.concurrent package instead.

aioobe
  • 383,660
  • 99
  • 774
  • 796
  • 1
    "_when dealing with volatile variables_ (...) _latest value written to the variable_" And with **non** `volatile` variables, there no such thing as "the latest value written to the variable". You need `volatile` for the phrase "the latest value written to the variable" to make sense. – curiousguy Oct 19 '11 at 03:18
  • 1
    I disagree. If I do `x = 1; x = 2;` in one thread, and then `System.out.println(x)` in another (*long after* `x = 2` has been executed, it may still print `1`. What I mean is that if `2` was the value last written to `x`, then `x` may still not evaluate to `2` in another thread. – aioobe Oct 19 '11 at 06:40
  • 1
    If `x` is not `volatile`: "_after `x = 2` has been executed_"/before `x = 2` has been executed **is not well defined**. If you really read `x` after it has been set to 2, then of course you will get 2. – curiousguy Oct 20 '11 at 12:40
4

Access to volatile int in Java will be thread-safe. When I say access I mean the unit operation over it, like volatile_var = 10 or int temp = volatile_var (basically write/read with constant values). Volatile keyword in java ensures two things :

  1. When reading you always get the value in main memory. Generally for optimization purposes JVM use registers or in more general terms local memory foe storing/access variables. So in multi-threaded environment each thread may see different copy of variable. But making it volatile makes sure that write to variable is flushed to main memory and read to it also happens from main memory and hence making sure that thread see at right copy of variable.
  2. Access to the volatile is automatically synchronized. So JVM ensures an ordering while read/write to the variable.

However Jon Skeet mentions rightly that in non atomic operations (volatile_var = volatile + 1) different threads may get unexpected result.

Saurabh
  • 7,703
  • 2
  • 20
  • 29
3

1) If two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use a synchronized in that case to guarantee that the reading and writing of the variable is atomic. Reading or writing a volatile variable does not block threads reading or writing. For this to happen you must use the synchronized keyword around critical sections.

2) As an alternative to a synchronized block you could also use one of the many atomic data types found in the java.util.concurrent package. For instance, the AtomicLong or AtomicReference or one of the others.

It's thread safe if you have one writer thread and multiple reader threads.

class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}

Note : If helper is immutable then no need of volatile keyword.Here singleton will work properly.

In case of counter which is being incremented by multiple threads (reading writing operation) will not give correct answer. This condition is also illustrated by race condition.

public class Counter{
private volatile int i;
public int increment(){
i++;
}
}

NOTE : Here volatile will not help.

Rahul Saxena
  • 628
  • 1
  • 9
  • 7
  • In Java, be careful to distinguish race condition and **data** race – curiousguy Jan 31 '18 at 12:43
  • Fun fact, the "Helper" example code with synchronization is broken on archaic Java Versions (up to 5) with JIT, see https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – domenukk May 26 '19 at 22:17
1

Not always.

It's not thread safe if multiple threads are writing and reading the variable. It's thread safe if you have one writer thread and multiple reader threads.

If you are looking for Thread safely, use AtomicXXX classes

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);

Refer to @teto answer in below post:

Volatile boolean vs AtomicBoolean

Community
  • 1
  • 1
Ravindra babu
  • 42,401
  • 8
  • 208
  • 194
  • @Ravindrababu - "It's not thread safe if multiple threads are writing and reading the variable" - i don't think this is true. The update of integer is atomic operation so even if multiple threads are writing to it, each would see the latest state (given its volatile). Order is not guaranteed though and would need locking... – Nrj Jan 07 '19 at 19:55
0

If a volatile is not dependent on any other volatile variable its thread safe for read operation. In case of write volatile does not guarantee thread safety.

Assume you have a variable i which is volatile and its value is dependent on another volatile variable say j. Now Thread-1 access variable j and increment it and is about to update it in main memory from CPU cache. In case the Thread-2 reads the
variable i before Thread-1 can actually update the j in main memory. The value of i will be as per the old value of j which would be incorrect. Its also called Dirty read.