Существует такая реализация синглтона на основе 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: Почему в данном классе не объявлен приватный конструктор? Ведь в случае его отсутствия где-то в коде можно явно создать экземпляр данного класса.
Это сделано, отчасти из за производительности, отчасти из за того, что если не использовать дополнительной локальной переменной, то код может работать не корректно.
А именно, если мы напишем в synchronized :
instance = new Singleton();
А Singleton будет иметь, например, такую структуру:
class Singleton {
private Object obj;
Singleton(){
obj = new Object();
}
}
То, компилятор может заинлайнить конструктор, при этом не сохранив порядок операций. Т.е. может получиться следующее:
SingletoninstanceТакая ситуация называется небезопасной публикацией. Чтобы ее исправить достаточно, определить поля либо final, либо volatile (есть еще варианты).
Хорошая статья с примерами на данную тему
PS. кому интересно, можете запустить у себя jsctress тест и поиграться с различными вариациями.
localInstance нужен для повышения производительности этого кода.
В случаях, когда instance уже инициализирован(т.е. в большинстве случаев)
это позволяет не обращаться к volatile полю второй раз,
при return instance вместо return localInstance
Источник: Joshua Bloch "Effective Java, Second Edition", p. 283-284
Там он утверждает, что это позволяет добиться прироста производительности в 25%
По поводу второго вопроса - полагаю, что приватный конструктор в синглтоне - нечто само собой разумеющееся.
Поэтому, при обсуждении более глубоких деталей реализации этот момент допустимо опустить.
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости