Очень простой подход - объявить loadMyItems
как synchronized
. Но если у класса есть другие методы, которые обращаются к myDef
, вы должны также объявить эти synchronized
. Иногда это приводит к очень грубой блокировке и снижению производительности.
Если вы ищете самый чистый / быстрый код, вместо объявления periodEviction
как synchronized
, объявите myDef
как AtomicReference
:
private final AtomicReference<MyDef> myDef = new AtomicReference<>();
Тогда тело periodEviction
есть:
synchronized (myDef) {
myDef.set(null);
}
А тело loadMyItems
это:
synchronized (myDef) {
if (myDef.get() == null) {
// perform initialization steps, ending with:
myDef.set(this.qDefFuture.get());
}
return myDef.get();
}
Если многие потоки вызывают loadMyItems
одновременно, myDef
будет когда-либо инициализирован только один раз, и все они получат один и тот же объект, возвращенный (если каким-то образом не вызовет periodEviction
в середине).