Is it necessary to make `AtomicBoolean` also `volatile`?

Tags: , , , ,



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:

  1. Every successful write by AtomicBoolean.compareAndSet() will eventually be visible to subsequent AtomicBoolean.get() and AtomicBoolean.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?

Answer

Is it necessary to make AtomicBoolean also volatile?

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.



Source: stackoverflow