What does AtomicBoolean do that a volatile boolean cannot achieve?
相关问题
- Delete Messages from a Topic in Apache Kafka
- Jackson Deserialization not calling deserialize on
- How to maintain order of key-value in DataFrame sa
- StackExchange API - Deserialize Date in JSON Respo
- Difference between Types.INTEGER and Types.NULL in
You can't do
compareAndSet
,getAndSet
as atomic operation with volatile boolean (unless of course you synchronize it).Boolean primitive type is atomic for write and read operations, volatile guarantees the happens-before principle. So if you need a simple get() and set() then you don't need the AtomicBoolean.
On the other hand if you need to implement some check before setting the value of a variable, e.g. "if true then set to false", then you need to do this operation atomically as well, in this case use compareAndSet and other methods provided by AtomicBoolean, since if you try to implement this logic with volatile boolean you'll need some synchronization to be sure that the value has not changed between get and set.
I use volatile fields when said field is ONLY UPDATED by its owner thread and the value is only read by other threads, you can think of it as a publish/subscribe scenario where there are many observers but only one publisher. However if those observers must perform some logic based on the value of the field and then push back a new value then I go with Atomic* vars or locks or synchronized blocks, whatever suits me best. In many concurrent scenarios it boils down to get the value, compare it with another one and update if necessary, hence the compareAndSet and getAndSet methods present in the Atomic* classes.
Check the JavaDocs of the java.util.concurrent.atomic package for a list of Atomic classes and an excellent explanation of how they work (just learned that they are lock-free, so they have an advantage over locks or synchronized blocks)
Remember the IDIOM -
READ - MODIFY- WRITE this you can't achieve with volatile
If there are multiple threads accessing class level variable then each thread can keep copy of that variable in its threadlocal cache.
Making the variable volatile will prevent threads from keeping the copy of variable in threadlocal cache.
Atomic variables are different and they allow atomic modification of their values.
They are just totally different. Consider this example of a
volatile
integer: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 onint
):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
andgetAndAdd(int delta)
, you can be sure that the result will be10
. In the same way, if two threads both negate aboolean
variable concurrently, with anAtomicBoolean
you can be sure it has the original value afterwards, with avolatile 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 exampleIf you have a thread running
loop()
and another thread callingstop()
, you might run into an infinite loop if you omitvolatile
, since the first thread might cache the value of stop. Here, thevolatile
serves as a hint to the compiler to be a bit more careful with optimizations.