My understanding: Declaring a variable volatile guarantees the visibility for other threads about writes to that variable. Essentially, every write to volatile variable happens-before subsequent reads.
I understand the atomicity of AtomicBoolean.compareAndSet() and how it provides the atomicity of read+write operation that volatile doesn't. But I don't see any doc providing visibility guarantee by AtomicBoolean like the following:
- Every successful
writebyAtomicBoolean.compareAndSet()will eventually be visible to subsequentAtomicBoolean.get()andAtomicBoolean.compareAndSet()by other threads.
But, I keep seeing code labelled as thread-safe which are like this,
// default false so that first-thread that execute() can enter the logic block
private static final AtomicBoolean executing = new AtomicBoolean(false);
public void execute() {
if (executing.compareAndSet(false, true)) { // check if the executing is previously false and if so update it to true
try {
// thead-safe code, i.e only one thread guaranteed to execute at any point of time time
} finally {
executing.set(false); // executing thread now re-sets the test value
}
}
}
Shouldn't the variable executing also declared volatile, like private static volatile AtomicBoolean executing = new AtomicBoolean(false); ? So the visibility guarantee needed by AtomicBoolean is achieved?
No.
In the example,
executingis declared asstatic 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
finalexcludes any subsequent assignments to the static that would negate the happens-before.You would only need to declare
executingasvolatileif 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 afinal, the memory model guarantees do not apply.)You would get a similar effect if
executingwasfinalbut an instance field rather than astaticfield. The reasoning is slightly different, but it is also explicitly mentioned in the JLS.Finally, the Java syntax does not allow you to combine
volatileandfinalmodifiers. That combination doesn't make sense.