Есть класс-кеш с отложенной инициализацией такого вида:
final class SyncTest {
private final Object NOT_INITIALIZED = new Object();
private Object object;
/**
* It's guaranteed by outer code that creation of this object is thread safe
* */
public SyncTest() {
object = NOT_INITIALIZED;
}
public Object getObject() {
if (object == NOT_INITIALIZED) {
synchronized (NOT_INITIALIZED) {
if (object == NOT_INITIALIZED) {
object = new AtomicReference(createObject()).get();
}
}
}
return object;
}
/**
* Creates some object which initialization is not thread safe
* @return required object or NOT_INITIALIZED
* */
private Object createObject() {
//do some work here
}
}
Ключевой момент здесь, строка:
object = new AtomicReference(createObject()).get();
Т.е. создается объект, присваивается volatile переменной (по сути AtomicReference), после чего присваивается не защищенной переменной object. Предполагаем, что возвращаемый объект неизменяем.
Корректен ли такой подход?
Все возможные варианты double-check-а из википедии просьба не предлагать. Интересует лишь корректность данного кода и чем причина ошибки, если он все-же не безопасен.