обновить память перед синхронизацией?
-
13-12-2019 - |
Вопрос
в модели памяти Java упоминается, что:Когда поток выходит из синхронизированного блока в рамках освобождения связанного монитора, JMM требует, чтобы кэш локального процессора был сброшен в основную память.Сходным образом, в рамках получения монитора при входе в синхронизированный блок локальные кэши становятся недействительными, поэтому последующие операции чтения будут идти непосредственно в основную память, а не в локальный кэш.
так почему в этом коде я должен объявить экземпляр как изменчивый, поскольку, когда второй поток входит в блок синхронизации, он перейдет непосредственно в основную память??
public final class MySingleton {
private static MySingleton instance = null;
private MySingleton() { }
public static MySingleton getInstance() {
if (instance == null) {
synchronized (MySingleton.class) {
if (instance == null) {
instance = new MySingleton();
}
}
}
return instance;
}
}
Я имею в виду, что когда другой поток входит в блок синхронизации и выполняет вторую проверку, он должен обновляться из основной памяти, как уже упоминалось.
Решение
Состояние гонки следующее:
Поток А видит
instance == NULL
и запускает этот кодinstance = new MySingleton();
.Напишите вinstance
видно, но запись вMySingleton
еще нет.Поток B видит
instance != NULL
и начинает работать над экземпляром.Поток B сейчас работает над объектом, конструкцию которого он не видит.
Изготовление instance
Летучий решает проблему, поскольку спецификация памяти JDK, начиная с JDK5, гарантирует, что запись в энергонезависимые объекты не будет нарушена по порядку по сравнению с записью в энергозависимый объект.Поэтому любой поток, который видит instance != NULL
должен видеть сам экземпляр.
Другие советы
Вы должны объявить его нестабильным, в противном случае нет никакой гарантии, что два вызова на GetInstance () вернут один и тот же экземпляр.
Нет гарантии, что доступная основная память будет доступна только последовательное значение кэша.I.e. Все темы увидят одинаковое значение.
BTW: Вы знаете, конечно, его гораздо более сложный, чем необходимо.Все, что вам нужно, это
public enum MySingleton {
INSTANCE;
}
.
делает много одно и то же.