I know, that in theory, to implement a correct singleton, in addition to double checked locking and synchronized
we should make an instance field volatile
.
But in real life I cannot get an example, that would expose the problem. Maybe there is a JVM flag that would disable some optimisation, or allow runtime to do such code permutation?
Here is the code, that, as I understand, should print to console from time to time, but it doesn't:
class Data {
int i;
Data() {
i = Math.abs(new Random().nextInt()) + 1; // Just not 0
}
}
class Keeper {
private Data data;
Data getData() {
if (data == null)
synchronized (this) {
if (data == null)
data = new Data();
}
return data;
}
}
@Test
void foo() throws InterruptedException {
Keeper[] sharedInstance = new Keeper[]{new Keeper()};
Thread t1 = new Thread(() -> {
while (true)
sharedInstance[0] = new Keeper();
});
t1.start();
final Thread t2 = new Thread(() -> {
while (true)
if (sharedInstance[0].getData().i == 0)
System.out.println("GOT IT!!"); // This actually does not happen
});
t2.start();
t1.join();
}
Could someone provide a code, that clearly demonstrates described theoretical lack of volatile
problem?