Issue
Given following code, in which I check a boolean value isInitialised
before running some code. if instead of
private static volatile boolean isInitialised;
, I use
private static final AtomicBoolean isInitialised = new AtomicBoolean(false);
,
it should achieve the same outcome and even the performance difference is negligible?
public class DclSingleton {
private static volatile boolean isInitialised;
//private static final AtomicBoolean isInitialised = new AtomicBoolean(false);
public static void doInit() {
if (!isInitialised) {
synchronized (DclSingleton.class) {
if (!isInitialised) {
// do init
isInitialised = true;
}
}
}
}
}
And if I do use AtomicBoolean
, would following code achieve the same?
public class DclSingleton {
// private static volatile boolean isInitialised;
private static final AtomicBoolean isInitialised = new AtomicBoolean(false);
public static void doInit() {
if (isInitialised.compareAndSet(false, true)) {
// do init
}
}
}
Solution
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.
Answered By - Solomon Slow