Volatile boolean vs AtomicBoolean
They are just totally different. Consider this example of a volatile
integer:
volatile int i = 0;
void incIBy5() {
i += 5;
}
If two threads call the function concurrently, i
might be 5 afterwards, since the compiled code will be somewhat similar to this (except you cannot synchronize on int
):
void incIBy5() {
int temp;
synchronized(i) { temp = i }
synchronized(i) { i = temp + 5 }
}
If a variable is volatile, every atomic access to it is synchronized, but it is not always obvious what actually qualifies as an atomic access. With an Atomic*
object, it is guaranteed that every method is "atomic".
Thus, if you use an AtomicInteger
and getAndAdd(int delta)
, you can be sure that the result will be 10
. In the same way, if two threads both negate a boolean
variable concurrently, with an AtomicBoolean
you can be sure it has the original value afterwards, with a volatile boolean
, you can't.
So whenever you have more than one thread modifying a field, you need to make it atomic or use explicit synchronization.
The purpose of volatile
is a different one. Consider this example
volatile boolean stop = false;
void loop() {
while (!stop) { ... }
}
void stop() { stop = true; }
If you have a thread running loop()
and another thread calling stop()
, you might run into an infinite loop if you omit volatile
, since the first thread might cache the value of stop. Here, the volatile
serves as a hint to the compiler to be a bit more careful with optimizations.
When is it preferable to use volatile boolean in Java rather than AtomicBoolean?
Essentially all AtomicBoolean
is a volatile boolean
in an object.
There will be a small overhead per object. Probably insignificant, but possibly more memory to get into cache.
If you need to use AtomicBooleanFieldUpdater
then there is quite a lot of performance overhead.It can be okay if you aren't going to do it often (as attach
in NIO).
AtomicBoolean vs volatile
using a AtomicBoolean
all read and write actions are atomic (as the name includes). with a volatile boolean
you still have to deal with race conditions, when two threads accessing the variable at the same time.
volatile vs Atomic boolean
AtomicBoolean and volatile have the exact same semantics in your usage (single writer), so either will work. The case for AtomicBoolean (or any Atomic class) is when you have to deal with multiple potential writers.
When do I need to use AtomicBoolean in Java?
When multiple threads need to check and change the boolean. For example:
if (!initialized) {
initialize();
initialized = true;
}
This is not thread-safe. You can fix it by using AtomicBoolean
:
if (atomicInitialized.compareAndSet(false, true)) {
initialize();
}
Is it necessary to make `AtomicBoolean` also `volatile`?
Is it necessary to make
AtomicBoolean
alsovolatile
?
No.
In the example, executing
is declared as static final
, so it will be initialized once at class initialization time and safely published to any other code that needs it.
This behavior is guaranteed because there is a happens-before between a classes initialization completing (normally) and any subsequent use of any static variable declared by the class. The fact that the variable is also final
excludes any subsequent assignments to the static that would negate the happens-before.
You would only need to declare executing
as volatile
if something could assign a new value to it after initialization. That's not possible here without doing some nasty reflection. (And the JLS states that if you do that kind of thing to change a final
, the memory model guarantees do not apply.)
You would get a similar effect if executing
was final
but an instance field rather than a static
field. The reasoning is slightly different, but it is also explicitly mentioned in the JLS.
Finally, the Java syntax does not allow you to combine volatile
and final
modifiers. That combination doesn't make sense.
Can AtomicBoolean replace volatile boolean?
There are two important differences between your two examples.
First, the obvious: The doInit()
method in your first example only sets isInitialized=true
after initializing the singleton. But, in your second example, it sets the AtomicBoolean
instance to true
before it initializes the singleton. That could be a problem if a second thread obtains a reference to the singleton after the flag has been set, but before the initialization has completed.
The second problem is less obvious: There is no synchronization after the flag is set in your second example. Nothing establishes a happens before relationship between the initialization code and anything that happens in some other thread. In your first example, the initialization happens before isInitialized=true
, and isInitialized=true
happens before any other thread tests if(!isInitialized)...
In your second example, if two threads concurrently call doInit()
, The Atomic operation ensures that only one of them can enter the initialization code. But even if the winner, by pure chance, actually completes the initialization code before* the other thread starts to use the singleton object, there still is no formal happens before relationship between the first thread doing the initialization and the second thread accessing the singleton.
* "before" in real time (a.k.a., wall clock time). If some event A actually happens before event B in real time, but there is no formal happens before relationship between the two events, then it is possible for some other thread to see the effects of those two events as if they happened in a different order.
Related Topics
Can't Make Jdbc Connection to MySQL (Using Java, Intellij, and Linux)
Inputstream.Available() Is 0 Always
How to Achieve Javafx Mouse Event "Push and Hold"
What Operations in Java Are Considered Atomic
What's the Syntax for Mod in Java
Java' Is Not Recognized as an Internal or External Command
How to Get Rjava 0.9-3 to Work on Os X 10.7.4 with Oracle Java 1.7
Ruby and Duck Typing: Design by Contract Impossible
Convert Existing Eclipse Project to Maven Project
Initializing Multiple Variables to the Same Value in Java
Calculating Distance Between Two Points, Using Latitude Longitude
When Exactly Do You Use the Volatile Keyword in Java