Есть связанные вопросы , но они в основном фокусируются на нестабильности, а не на использовании локальной переменной, поэтому я отправляю новый вопрос, см. Вопрос ниже.
Источник сонара Правило имеет код, в соответствии с которым приведенный ниже код является правильным, и решает проблемы с DCL
class ResourceFactory {
private volatile Resource resource;
public Resource getResource() {
Resource localResource = resource;
if (localResource == null) {
synchronized (this) {
localResource = resource;
if (localResource == null) {
resource = localResource = new Resource();
}
}
}
return localResource;
}
static class Resource {
}
}
Я понимаю, что у нас есть альтернативные варианты (некоторые лучше, чем сложные DCL), такие как
- enum или
- статический внутренний классодержатель или
- статическая конечная ссылка, инициализированная во время самого объявления.
- объявить весь метод синхронизированным.
Я хочу понять использование volatile вместе с локальной переменной для решения проблем с DCL.
Также я понимаю, что volatile (для Java 1.5 и более поздних версий) гарантирует функцию «происходит до», которая предотвращает возврат не полностью завершенного объекта для чтения.
Вопрос 1 Я хочу понять, для чего нужна переменная, если локальная переменная уже использовалась. Ниже в коде есть энергонезависимая переменная resource
, но внутри getResource()
локальная переменная используется для чтения resource
. Есть ли еще проблемы в коде? (см. Комментарии ниже по коду ниже)
class ResourceFactory {
private Resource resource; // non volatile
public Resource getResource() {
Resource localResource = resource; // only 1 read without lock
if (localResource == null) {
synchronized (this) {
localResource = resource; // read inside the synchronized block
if (localResource == null) {
localResource = new Resource(); // constructor is initialized.
resource = localResource; // ****code reaches here only when constructor has been complete. Here is there a chance of resource being referring to incomplete object ?****
}
}
}
return localResource;
}
static class Resource {
}
}
Единственное преимущество, которое я вижу в volatile, это предположить, что объект был создан, тогда первое чтение само по себе гарантировало бы чтение из памяти, а не чтение из кэша потока, предотвращая ненужное получение блокировки.
Вопрос 2 Вместо использования локальной переменной, если использовалась простая переменная, тогда был ли код без проблем?