Творческий шаблон: синглтон
В этой статье обсуждается, как шаблон Singleton обеспечивает создание и существование только одного экземпляра класса в течение всего времени существования приложения.

Что это?
Синглтон — это шаблон проектирования, используемый для создания единственного экземпляра класса. Шаблон Singleton обычно используется, когда есть несколько примеров, в которых должен существовать только один экземпляр класса и должно применяться ограничение. Например, кэши, пулы потоков и реестры должны иметь только один экземпляр.
Сделайте конструктор закрытым, чтобы гарантировать создание только одного объекта класса. Таким образом, только члены класса могут получить доступ к частному конструктору и никто другой.
В реальном мире шаблон Singleton гарантирует, что существует только один экземпляр класса, и предлагает глобальную точку доступа к нему.
Диаграмма классов
Диаграмма классов содержит только одну сущность.
Синглтон

Пример
Допустим, мы хотим смоделировать официальный самолет американского президента под названием Airforce One в нашем программном обеспечении. Класс Singleton — это наиболее подходящее представление для сущности только с одним экземпляром.
Вот код для нашего одноэлементного класса:

Многопоточность и синглтон
Этот код работает, пока приложение является однопоточным. Однако, если несколько потоков обращаются к этому классу, существует вероятность того, что будут созданы различные объекты.
Например:
- Поток A вызывает метод
getInstance
и находитonlyInstance
значение null; однако, прежде чем он сможет создать экземпляр, он отключается от контекста. - Теперь появляется поток B и вызывает
getInstance
, который возвращаетAirforceOne
объект. - Если поток A снова планируется, начинаются шалости. Поток уже прошел проверку условия if-null и приступит к созданию нового
AirforceOne
объекта и назначению егоonlyInstance
.AirforceOne
Теперь в дикой природе есть два разных объекта, один с потоком A и один с потоком B.
- Добавляя
synchronized
вgetInstance()
метод, можно добиться потокобезопасности. - Другой вариант — инициализировать экземпляр статически, гарантируя его потокобезопасность.


Блокировка с двойной проверкой
У описанных выше подходов есть две существенные проблемы: синхронизация требует больших затрат, а статическая инициализация создает объект, даже если он не используется в конкретном запуске приложения. Если создание объекта обходится дорого, то статическая инициализация может стоить нам производительности.

Приведенное выше решение помечает экземпляр singleton как volatile. Однако эта реализация методологии JVM volatile
не будет работать правильно для блокировки с двойной проверкой, и вам потребуется другой подход для создания ваших синглетонов.
Идиома блокировки с двойной проверкой теперь считается антипаттерном, и ее полезность в основном исчезла, поскольку время запуска JVM ускорилось.
Другие примеры
Java API предоставляет нам следующие синглтоны:
java.lang.Время выполнения
java.awt.Рабочий стол
Предостережения
Вы можете создать подкласс одноэлементного класса, защитив конструктор вместо частного. Тем не менее, есть лучшие варианты, чем это при любых обстоятельствах. В таких ситуациях разработчики могут создать реестр синглетонов для всех подклассов. Метод getInstance может принимать параметр или использовать переменную среды для возврата желаемого одноэлементного объекта. Реестр поддерживает сопоставление строковых имен с одноэлементными объектами.