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

JavaTalks.Patterns.Singleton

  • 1.
    Глобальный объект Пулыпотоков Пулы соединений Управление реестрами, конфигурацией ...
  • 2.
  • 3.
  • 4.
    Объект? о_О Объектдолжен создаваться единственный раз Объект должен быть доступен другим объектам Возможно ли это?
  • 5.
    Реализация Конструктор объявленкак private Экземпляр создается внутри класса и лишь один раз Экземпляр возвращает статический метод
  • 6.
    Результат Объект создаетсялишь один раз getInstance() возвращает всегда один и тот же объект Объект виден для любого другого объекта
  • 7.
    Мне мало! Маломне, хочу еще… хочу еще чего-нибудь.. хочу еще ленивую загрузку!
  • 8.
    Ленивая загрузка?! Ведь,статические члены класса загружаются только при первом обращении к классу…
  • 9.
    Не все такпросто! Да, instance создастся только при первом обращении к классу, однако не обязательно это обращение произойдет к getInstance() . Наш класс может содержать другие статические члены, например, методы или константы. Тогда экземпляр класса может создаться в любой момент времени…
  • 10.
  • 11.
    Результат Но чтопроизойдет, если этот Singleton будет работать в многопоточной среде? Этот метод не защищен от одновременного обращения к нему нескольких потоков:
  • 12.
    Синхронизируем! Теперь нашметод полностью защищен, можем его использовать в своих приложениях!
  • 13.
    Low performance Синхронизированныеметоды снижают производительность: Синхронизированный метод запускается в 2-3 раза медленней Если один поток зайдет в синхронизированный блок, остальные будут ждать пока первый не выйдет. А количество потоков в крупных приложениях может быть немалым…
  • 14.
    Double-check locking Хитроерешение: теперь синхронизация нам потребуется только при создании объекта! Это называется double-check locking .
  • 15.
    Результат Объект создаетсялишь один раз getInstance() возвращает всегда один и тот же объект Объект виден для любого другого объекта Lazy initialization Потоко-безопасность Высокая производительность
  • 16.
  • 17.
    ЧЕГО?! Однако этотметод НЕ потоко-безопасен!
  • 18.
    Как так?! Номы синхронизировали блок создания объекта! Как такое возможно?!
  • 19.
    Истина печальна… Всебы было хорошо, если б не было так плохо. Дело в том, что double-check locking в Java не работает . Это не баг, это связано с устройством Java Memory Model (JMM). Создание объекта происходит в несколько этапов: Под объект выделяется память Ссылка на объект получает свое значение Вызывается конструктор объекта Таким образом инициализация объекта может быть еще не завершена, а другой поток поглядит, что ссылка не null и будет использовать его еще сырым.
  • 20.
    Бездну не перепрыгнутьМногие пытались обойти эту проблему, однако безуспешно…
  • 21.
    Volatile Единственное решение– это использование ключевого слова volatile: Однако, как заметил Allen Holub, volatile может привести к серьезным проблемам с производительностью на мультипроцессорных машинах. К тому же, не во всех JVM volatile реализовано полноценно. Детальней: спецификация JSR 133.
  • 22.
    Где же выход?Выходит решения нет?!
  • 23.
    Есть! =) Выходнашел Bill Pugh и он так и был назван решением Билла Пью “Initialization on Demand Holder”:
  • 24.
    How does itwork? Ленивая загрузка обеспечена тем, что обращаемся мы к внутреннему классу только в методе getInstance() Синхронизация обеспечена тем, что обратиться к статическому полю мы сможем только к тому моменту, когда класс полностью загружен и его статический блок выполнен
  • 25.
    Исключения? Конструктор можетвыбросить исключение? В Java есть понятие статического блока! Забыли?
  • 26.
    Можете быть спокойныБольше не придется нервничать
  • 27.
    Наслаждайтесь жизнью Небудет подвохов и печальных открытий. Мы нашли идеальный способ, который удовлетворяет все наши потребности.
  • 28.
    Мир полон разнообразий…Однако есть еще вариант:
  • 29.
    Enum? о_ОДа, это enum ! Интересное и вполне работоспособное решение. К тому же решает еще одну проблему, которую мы не рассмотрели, – сериализация.
  • 30.
    Enum? о_ОДа, это enum ! Интересное и вполне работоспособное решение. К тому же решает еще одну проблему, которую мы не рассмотрели, – сериализация.
  • 31.
    Singleton serialization Еслимы сериализовали Singleton , а потом дважды десериализовали, то получим ДВА разных объекта.
  • 32.
    enum + serialization= love Enum позволяет корректно работать с сериализацией.
  • 33.
    УСЬО! Итак, мырассмотрели все основные виды Одиночек: Обычный, без ленивой загрузки Однопоточный с ленивой загрузкой Многопоточный с синхронизированным методом Решение Билла Пью “Initialization on Demand Handler” Enum Из всех способов вы вольны выбирать любой, который подходит под вашу конкретную ситуацию.
  • 34.
    У Одиночки естьмного проблем
  • 35.
    Подводные камни Одиночки…Невозможность наследования “ Single class – single responsibility” violation Сложности при тестировании Когда одиночка не одинок… Java 1.2 + Singleton = вигвам
  • 36.
    Singleton sucks Singeton== antipattern?
  • 37.