#java #многопоточность
Существует такая реализация синглтона на основе double checked locking (пункт 2):
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
Singleton localInstance = instance;
if (localInstance == null) {
synchronized (Singleton.class) {
localInstance = instance;
if (localInstance == null) {
instance = localInstance = new Singleton();
}
}
}
return localInstance;
}
}
Вопрос 1: для чего здесь используется localInstance? Почему бы не сделать вот так:
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
?
У меня есть предположение: чтение volatile-поле обходится несколько дороже, чем чтение
обычного поля, либо локальной переменной, поэтому здесь и используется локальная переменная.
Если я прав и кто-то может расписать этот момент по-подробнее - буду признателен.
Вопрос 2: Почему в данном классе не объявлен приватный конструктор? Ведь в случае
его отсутствия где-то в коде можно явно создать экземпляр данного класса.
Ответы
Ответ 1
Это сделано, отчасти из за производительности, отчасти из за того, что если не использовать дополнительной локальной переменной, то код может работать не корректно. А именно, если мы напишем в synchronized : instance = new Singleton(); А Singleton будет иметь, например, такую структуру: class Singleton { private Object obj; Singleton(){ obj = new Object(); } } То, компилятор может заинлайнить конструктор, при этом не сохранив порядок операций. Т.е. может получиться следующее: Создается объект Singleton Присваивается значению instance Инициализируются поля у созданного объекта Такая ситуация называется небезопасной публикацией. Чтобы ее исправить достаточно, определить поля либо final, либо volatile (есть еще варианты). Хорошая статья с примерами на данную тему PS. кому интересно, можете запустить у себя jsctress тест и поиграться с различными вариациями.Ответ 2
localInstance нужен для повышения производительности этого кода. В случаях, когда instance уже инициализирован(т.е. в большинстве случаев) это позволяет не обращаться к volatile полю второй раз, при return instance вместо return localInstance Источник: Joshua Bloch "Effective Java, Second Edition", p. 283-284 Там он утверждает, что это позволяет добиться прироста производительности в 25% По поводу второго вопроса - полагаю, что приватный конструктор в синглтоне - нечто само собой разумеющееся. Поэтому, при обсуждении более глубоких деталей реализации этот момент допустимо опустить.
Комментариев нет:
Отправить комментарий