Лучший способ упростить его, IMO, - это использовать «нормальную» блокировку, если у вас нет убедительных доказательств того, что она вызывает узкое место:
private final Object lock = new Object();
private ProductCatalog productCatalog;
public ProductCatalog get() {
synchronized (lock) {
if (this.productCatalog == null) {
this.productCatalog = productCatalogLoader.load();
}
return this.productCatalog;
}
}
В подавляющем большинстве случаев этого будет достаточно, и вам не нужно беспокоиться о технических особенностях модели памяти.
РЕДАКТИРОВАТЬ: относительно того, является ли чтение данных, измененных в блокировке записи без получения блокировки чтения, безопасно - я подозреваю нет, но я не хотел бы сказать наверняка. Есть ли какая-то польза в вашем подходе к использованию обычной (и безопасной на Java 1.5+, если вы осторожны) двойной проверки блокировки с использованием переменной volatile?
private final Object lock = new Object();
private volatile ProductCatalog productCatalog;
public ProductCatalog get() {
if (this.productCatalog == null) {
synchronized (lock) {
if (this.productCatalog == null) {
this.productCatalog = productCatalogLoader.load();
}
}
}
return this.productCatalog;
}
Я полагаю, что это ленивая методика инициализации, рекомендуемая в Effective Java 2nd edition, для ситуаций, когда статических инициализаторов недостаточно. Обратите внимание, что productCatalog
должен быть нестабильным, чтобы это работало - и я думаю, что это эффективно , чего вам не хватает, не снимая блокировку чтения в вашем коде.