#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% По поводу второго вопроса - полагаю, что приватный конструктор в синглтоне - нечто само собой разумеющееся. Поэтому, при обсуждении более глубоких деталей реализации этот момент допустимо опустить.
Комментариев нет:
Отправить комментарий