Блокировка с двойной проверкой и синглтоны — ссылка на исходный текст
Блокировка с двойной проверкой и синглтоны — ссылка на исходный текст
Блокировка с двойной проверкой и синглтоны — ссылка на исходный текст
Я считаю, что для шаблона синглтона большинство людей могут написать несколько методов реализации, таких как ленивые люди, голодные люди и т. д. Однако хорошо написать маленькие синглтоны непросто, и не просто написать их полностью.
Синглтон для замков с двойной проверкой
Ниже приведена реализация синглтона, которую мы часто используем, то есть реализация двойной проверки.
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton(); // error
}
}
}
return uniqueSingleton;
}
}
Давайте посмотрим, как работает этот код: во-первых, когда поток делает запрос, он сначала проверяет, является ли экземпляр нулевым, и если нет, возвращает его содержимое напрямую, избегая тем самым ресурсов, необходимых для входа в синхронизированный блок. Во-вторых, если два потока входят в первое if-суждение одновременно, то они также должны выполнять код в синхронизированном блоке по порядку.Первый поток, входящий в блок кода, создаст новый экземпляр Singleton, а последующие потоки будут выполняться, потому что of Невозможно судить по if без создания избыточных экземпляров.
Но все же есть проблема, в некоторых случаях полученный таким образом объект Singleton может быть неправильным.
Просмотрите 3 шага нашего нового объекта
-
1. Выделить место в памяти
-
2. Инициализировать объект
-
3. Укажите объект на только что выделенное пространство памяти
Однако, когда jvm оптимизирует инструкции, шаги 2 и 3 будут обратными. Например, после того, как поток 1 признан нулевым на двух уровнях, он переходит к новому действию. Если объект не был инициализирован, значение адреса возвращается, и поток 2. В первом нулевом решении, поскольку объект не пустой, объект возвращается напрямую. Однако когда поток 2 намеревается использовать экземпляр Singleton, он обнаруживает, что он не был инициализирован, и возникает ошибка.
решение
Для вышеуказанной проблемы есть два решения
1. Использование ключевого слова volatile в основном гарантирует, что порядок выполнения кода не повлияет на переупорядочивание jvm.
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
}
public Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton(); // error
}
}
}
return instance;
}
}
2. Реализовать одноэлементный шаблон в многопоточной среде с помощью внутренних классов.
public class Singleton {
private Singleton() {
}
private static class SingletonContainer {
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonContainer.instance;
}
}