Для выполнения незапираемой и ожидающей ленивой инициализации я делаю следующее:
private AtomicReference<Foo> instance = new AtomicReference<>(null);
public Foo getInstance() {
Foo foo = instance.get();
if (foo == null) {
foo = new Foo(); // create and initialize actual instance
if (instance.compareAndSet(null, foo)) // CAS succeeded
return foo;
else // CAS failed: other thread set an object
return instance.get();
} else {
return foo;
}
}
и он работает очень хорошо, за исключением одного: если два потока видят экземпляр null
, они оба создают новый объект, и только одному повезет установить его с помощью операции CAS, что приводит к расходованию ресурсов.
Кто-нибудь предлагает другой незаметный ленивый шаблон инициализации, который уменьшает вероятность создания двух дорогостоящих объектов двумя параллельными потоками?