Объект? о_О Объектдолжен создаваться единственный раз Объект должен быть доступен другим объектам Возможно ли это?
5.
Реализация Конструктор объявленкак private Экземпляр создается внутри класса и лишь один раз Экземпляр возвращает статический метод
6.
Результат Объект создаетсялишь один раз getInstance() возвращает всегда один и тот же объект Объект виден для любого другого объекта
7.
Мне мало! Маломне, хочу еще… хочу еще чего-нибудь.. хочу еще ленивую загрузку!
8.
Ленивая загрузка?! Ведь,статические члены класса загружаются только при первом обращении к классу…
9.
Не все такпросто! Да, instance создастся только при первом обращении к классу, однако не обязательно это обращение произойдет к getInstance() . Наш класс может содержать другие статические члены, например, методы или константы. Тогда экземпляр класса может создаться в любой момент времени…
Результат Но чтопроизойдет, если этот Singleton будет работать в многопоточной среде? Этот метод не защищен от одновременного обращения к нему нескольких потоков:
Low performance Синхронизированныеметоды снижают производительность: Синхронизированный метод запускается в 2-3 раза медленней Если один поток зайдет в синхронизированный блок, остальные будут ждать пока первый не выйдет. А количество потоков в крупных приложениях может быть немалым…
14.
Double-check locking Хитроерешение: теперь синхронизация нам потребуется только при создании объекта! Это называется double-check locking .
15.
Результат Объект создаетсялишь один раз getInstance() возвращает всегда один и тот же объект Объект виден для любого другого объекта Lazy initialization Потоко-безопасность Высокая производительность
Как так?! Номы синхронизировали блок создания объекта! Как такое возможно?!
19.
Истина печальна… Всебы было хорошо, если б не было так плохо. Дело в том, что double-check locking в Java не работает . Это не баг, это связано с устройством Java Memory Model (JMM). Создание объекта происходит в несколько этапов: Под объект выделяется память Ссылка на объект получает свое значение Вызывается конструктор объекта Таким образом инициализация объекта может быть еще не завершена, а другой поток поглядит, что ссылка не null и будет использовать его еще сырым.
Volatile Единственное решение– это использование ключевого слова volatile: Однако, как заметил Allen Holub, volatile может привести к серьезным проблемам с производительностью на мультипроцессорных машинах. К тому же, не во всех JVM volatile реализовано полноценно. Детальней: спецификация JSR 133.
Есть! =) Выходнашел Bill Pugh и он так и был назван решением Билла Пью “Initialization on Demand Holder”:
24.
How does itwork? Ленивая загрузка обеспечена тем, что обращаемся мы к внутреннему классу только в методе getInstance() Синхронизация обеспечена тем, что обратиться к статическому полю мы сможем только к тому моменту, когда класс полностью загружен и его статический блок выполнен
УСЬО! Итак, мырассмотрели все основные виды Одиночек: Обычный, без ленивой загрузки Однопоточный с ленивой загрузкой Многопоточный с синхронизированным методом Решение Билла Пью “Initialization on Demand Handler” Enum Из всех способов вы вольны выбирать любой, который подходит под вашу конкретную ситуацию.
Подводные камни Одиночки…Невозможность наследования “ Single class – single responsibility” violation Сложности при тестировании Когда одиночка не одинок… Java 1.2 + Singleton = вигвам