When is it preferable to use volatile boolean in Java rather than AtomicBoolean? [duplicate]
I've looked at the other volatile vs. Atomicxxxx questions in SO (including this one) and have read the description of java.util.current.atomic, and I am not quite satisfied with the nuances.
If I'm trying to decide between using volatile boolean
and AtomicBoolean
, are there practical differences besides the atomic read-modify-write operations offered by AtomicBoolean? (e.g. compareAndSet()
and getAndSet()
)
Suppose I have
volatile boolean flag;
Then one or more threads set the flag (but not clear it). If I have one thread that reads the flag, and if set, does an action, and then clears the flag, is volatile
adequate?
Is there a higher cost to AtomicBoolean than volatile boolean, in terms of
- memory space
- performance hit (
volatile boolean
appears to require memory fencing,AtomicBoolean
appears to require memory fencing + some minor locking on CAS operations as per the java.util.current.atomic description)
My gut call is to just go with AtomicBoolean and be safe, but I want to understand if there's ever a situation to use volatile boolean
instead (e.g. if I had thousands of instances of them and performance were an issue).
The main difference between AtomicBoolean
and volatile
from a practical point of view is that the compare-and-set operation isn't atomic with volatile
variables.
volatile boolean b;
void foo() {
if( b ) {
//Here another thread might have already changed the value of b to false
b = false;
}
}
But seeing as all your concurrent writes are idempotent and you only read from one thread, this shouldn't be a problem.
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).
I'm not sure I completely agree with the other answers here; biziclop's answer is right as far as it goes, but I'm not sure we can conclude that you're safe unless we know more detail.
In the simple case, interleaving might look like this:
Thread 1 (writer) Thread 2 (Writer) Thread 3 (Reader)
----------------- ----------------- -----------------
flag = true;
if (flag) {
flag = true;
flag = false;
doStuff();
and this might be fine (the second set of flag
to true
doesn't matter, as doStuff()
will still presumably see whatever Thread 2 needs doing.
However if you reverse the order thread 3 does:
Thread 1 (writer) Thread 2 (Writer) Thread 3 (Reader)
----------------- ----------------- -----------------
flag = true;
if (flag) {
doStuff();
flag = true;
flag = false;
then Thread 2's update could be lost.
Of course you need to be similarly careful with whatever else Thread 2 does, to make sure it's visible to Thread 3. If there's other state that Thread 2 needs to set, order becomes important there too.
In the simple case, yes you're fine, but if it gets more complex than just simple flicking of flags then this becomes much harder to reason about.
There is a lot of good information here. However, I would add another difference that may be useful. You can have an array of AtomicBooleans but you can't (to my knowledge) have an array of volatile booleans.
Then one or more threads set the flag (but not clear it). If I have one thread that reads the flag, and if set, does an action, and then clears the flag, is volatile adequate?
Yes, if you don't need the special abilities of AtomicBoolean, it's perfectly fine to use volatile for this. In fact, this is one of the few reasonable uses for volatile.
精彩评论