Comments 93
хорошая статья, пишите больше)
+3
Спасибо за статью.
Может быть стоит переместить ее в блог по Java: http://habrahabr.ru/blog/java/ ?
Может быть стоит переместить ее в блог по Java: http://habrahabr.ru/blog/java/ ?
0
Я не думаю, не смотря на то, что статья Java-ориентированная, она все же больше относиться к "Совершенному коду", на мой взгляд.
+1
А у вас нет желания опубликовать серию статей по Java? Это было бы очень полезно.
0
Кстати, добавте в статью те случаи, когда Singelton является антипаттерном. Например, когда в него засовывают "глобалбные" переменные.
+3
В данной статье я специально опустил эти детали и сконцентрировался только на реализации singleton функционала. Но я с вами согласен, есть множество неправильных использований синглтона, которые только вредят дизайну.
0
Как раз знание этих вещей поможет писать совершенный код. Вам был бы огромный респект и плюс в карму (хотя я уже плюсанул :-)), если бы вы изучили эти случаи и дополнили ими статью.
0
Этих случаев достаточно много, и они, скорей всего, относятся к несовершенному дизайну, а не к несовершенному коду. Возьмем ваш пример - "..когда в него засовывают "глобалбные" переменные..", с точки зрения кода, все может работать отлично, но с точки зрения дизайна - ряд проблем на лицо.
0
не согласен. синглтон прекрасно может хранить глобальные переменные.
Наглядный пример: паттерн Registry
Наглядный пример: паттерн Registry
0
Где ж тут про переменные сказано?
0
Статья интересная безусловно. Одно замечание - я бы вместо термина "аппликация" использовал "приложение". Режет глаза термин.
0
огромное спасибо за статью.был бы вам очень признателен,если бы вы писали еще что нибудь про Java:)
+2
Когда делали скриншоты с Эклипса, то 2, 3 и 4я картинки получили размазаны.
0
Почему в первом примере для многопоточной среды нельзя сделать вызов getInstance() синхронизованым (synchronized) ? Это решило бы сразу все проблемы.
0
Именно это я и сделал в 4-ом варианте решения.
0
Ну у вас какой-то обходной путь. Как только вы поняли, что оно не подходит для multi-thread, вы начали не пойми что придумывать, когда надо только добавить "synhronized"
0
Не буду с вами спорить.
0
Да. Спорить наверное не нужно, ибо DOKA сделал неплохое замечание. Я также когда читал, споткнулся на этом месте. Ну раз не многопоточный, то стало быть и желательно одним предложением написать почему он такой и добавить, что логично, разумеется, воткнуть synchronized и закрыть вопрос. Сославшись на то, что такой случай будет рассмотрен ниже и у него есть свой нюанс.
Второй момент который чуть резанул глаз, это фраза - Реализация Singleton в JAVA. Я не знаю прав я или нет с точки зрения моего интуитивного ощущения русского языка, но когда я вижу фразу ..В Java… я ожидаю, что это УЖЕ реализовано внутри самой платформы и человек просто описывает как там это сделано. Если же речь идёт о том как самому реализовать что-то средствами языка, я ожидаю увидеть оборот ...НА Java.. То есть - как мне реализовать это на языке Java.
Что же касается статьи в целом, то наверное это одна из самых толковых технических статей на Хабре за долгий период. Обычно люди, когда вставляют куски кода в статью, вырывают их из контекста и этот контекст не описывают. То есть пишут в духе ... я вот вчера ночью, лихорадочно кодируя (препарируя вирус...)... открыл для себя, что тут можно было вставить вот такой крутой оператор... а посему на утро хочу поделиться этим с хабра-людьми. Это всё хорошо, но... Что кодировал? Куда вставил? Зачем вставил и кому это нужно?
У вас действительно чётко и внятно описан ходовой и нужный паттерн, и приведены основные варианты его реализации с их плюсами и минусами. Статья логически закончена и реально полезна разработчику. Просто как букварь. Лан, не буду тут раcшаркиваться :-), но что хотел сказать, то сказал.
Второй момент который чуть резанул глаз, это фраза - Реализация Singleton в JAVA. Я не знаю прав я или нет с точки зрения моего интуитивного ощущения русского языка, но когда я вижу фразу ..В Java… я ожидаю, что это УЖЕ реализовано внутри самой платформы и человек просто описывает как там это сделано. Если же речь идёт о том как самому реализовать что-то средствами языка, я ожидаю увидеть оборот ...НА Java.. То есть - как мне реализовать это на языке Java.
Что же касается статьи в целом, то наверное это одна из самых толковых технических статей на Хабре за долгий период. Обычно люди, когда вставляют куски кода в статью, вырывают их из контекста и этот контекст не описывают. То есть пишут в духе ... я вот вчера ночью, лихорадочно кодируя (препарируя вирус...)... открыл для себя, что тут можно было вставить вот такой крутой оператор... а посему на утро хочу поделиться этим с хабра-людьми. Это всё хорошо, но... Что кодировал? Куда вставил? Зачем вставил и кому это нужно?
У вас действительно чётко и внятно описан ходовой и нужный паттерн, и приведены основные варианты его реализации с их плюсами и минусами. Статья логически закончена и реально полезна разработчику. Просто как букварь. Лан, не буду тут раcшаркиваться :-), но что хотел сказать, то сказал.
0
А performance?
Если getInstance() вызывается в циклах постоянно?
Если getInstance() вызывается в циклах постоянно?
0
Если надо вызывать из цикла, то можно использовать вар. №5. В остальных случаях в угоду читаемости следует использовать sinhronized на метод. И что-то мне подсказывает, что результат в действительности будет не сильно различаться.
0
UFO just landed and posted this here
Ещё бы кто-нибудь на Хабре написал beginners tutorial по Hibernate.. Было бы клёво :)
0
Будет время - напишу. Чем вас не устраивает туториал, который находится на оффсайте Hibernate? Или этот, например, если вам нужно на русском языке http://www.javaportal.ru/java/articles/h….
0
О реализации синглетонов на C++ хорошо написано у Александреску. Может, и явистам будет интересно почитать.
+2
отличная статья
0
В Scala ("the new java") это реализовано на уровне синтаксиса языка - можно объявлять сразу object, а не class
+1
Это не совсем то же самое хочется ленивой инстанциации
0
это порочное желение.
Если хочется ленивой загрузки, значит у объекта есть жизненный цикл (например, взаимодействие с каким-нубдь ресурсом или большие требования памяти / cpu). А это уже по определению не Singleton
Если хочется ленивой загрузки, значит у объекта есть жизненный цикл (например, взаимодействие с каким-нубдь ресурсом или большие требования памяти / cpu). А это уже по определению не Singleton
0
круто, спасибо! :)
большую часть информации я и так знал, но некоторые моменты были познавательными.
IJ Idea, кстати, автоматом по дефолту генерит второй вариант
большую часть информации я и так знал, но некоторые моменты были познавательными.
IJ Idea, кстати, автоматом по дефолту генерит второй вариант
0
было бы здорово если бы в подобном очень дружелюбном изложении
на хабре написал бы кто-нибудь пару статей и про другие основные шаблоны
а конкретно с примерами их использования в своих проектах
книжки книжками, но там всегда одни и те же везде примеры - как будто все только и делают, что
клепают интернет магазины и студентов в базу заносят
на хабре написал бы кто-нибудь пару статей и про другие основные шаблоны
а конкретно с примерами их использования в своих проектах
книжки книжками, но там всегда одни и те же везде примеры - как будто все только и делают, что
клепают интернет магазины и студентов в базу заносят
+2
Отличная статья! Автору спасибо! Побольше бы таких :)
0
с нетерпением буду ждать продолжение и о яве, и по тематике блога.
автору — спасибо!
автору — спасибо!
0
Будет нелишне добавить
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
0
Спасибо.
0
Статья интересная, плюсанул, но. Но нужно помнить об осторожности и технике безопасности. Когда даете детям в руки такую игрушку, очень важно упомянуть, как НЕ НАДО ей играться, а то так сдуру и тесты сломать можно.
Синглтон выглядит очень привлекательно, а на самом деле во многих популярных случаях это все-таки антипаттерн.
Синглтон выглядит очень привлекательно, а на самом деле во многих популярных случаях это все-таки антипаттерн.
+1
Синглетон полезный и нужный паттерн для чётко очерченных случаев, тщательно описанных в его описании. Называть его антипаттерном, это как называть кухонный нож вредным инструментом на том простом основании, что им можно кого-то зарезать. Ну да, наверное можно, но если бы он сопровождался инструкцией, там было бы внятно написано, что им нужно картошку чистить. И только.
В противном случае большинство окружающих нас вещей можно было бы легко зачислить в антипаттерны. Авто, качели, табуретки... Антипаттерн – это неправильное использование нужной и полезной вещи. Из этого абсолютно никак не следует, что мы не должны знать и шарахаться правильного применения нужных и полезных вещей. :-)
В противном случае большинство окружающих нас вещей можно было бы легко зачислить в антипаттерны. Авто, качели, табуретки... Антипаттерн – это неправильное использование нужной и полезной вещи. Из этого абсолютно никак не следует, что мы не должны знать и шарахаться правильного применения нужных и полезных вещей. :-)
+1
enum Singleton {
INSTANCE;
public static Singleton getInstance() { return INSTANCE; }
}
INSTANCE;
public static Singleton getInstance() { return INSTANCE; }
}
0
минусующему предлагаю почитать мнение Блоха, который, как ни странно, тоже считает, что a single-element enum type is the best way to implement a singleton.
+1
Действительно, очень интересный вариант. Испаравил социальную несправедливость, где только мог. Спасибо.
0
Честно говоря, я не могу доказать, что в данном случае гарантирована безопасность в многопоточной среде, но я на 95% уверен, что авторы спецификации Java5 это предусмотрели. Надо будет порыться в спецификации или дизассемблировать какой-нибудь пример.
0
примерчик дизассемблировал, все нормально там с многопоточностью, по структуре реализация enum это развитие второго варианта, со всеми наворотами enum'ов, которые, цитируя Блоха, добавляют лаконичность синтаксического сахара, сериализацию "из коробки", и серьезную безопасность, в т.ч. от разных изощренных атак.
0
в
enum Singleton {
INSTANCE;
public static Singleton getInstance() { return INSTANCE; }
}
public static Singleton getInstance() { return INSTANCE; }
строчка лишняя имхо.
Если уж enum , то Singleton.INSTANCE
enum Singleton {
INSTANCE;
public static Singleton getInstance() { return INSTANCE; }
}
public static Singleton getInstance() { return INSTANCE; }
строчка лишняя имхо.
Если уж enum , то Singleton.INSTANCE
0
Пара замечаний по 5 пункту.
1. volatile вообще-то считается самым быстрым способом синхронизации в Java. Быстрее бывает только полное отстуствие синхронизации. Более того: в режиме чтения, который используется в примере, скорость доступа к volatile переменной практически не отличается от скорости доступа к несинхронизированной переменной. Товарищ Allen Holub был здесь неправ, или его неправильно поняли.
2. Корректная работа данного когда под Java версии < 1.5 тоже не гарантируется :)
Подробнее можно почитать у Билла Пью
1. volatile вообще-то считается самым быстрым способом синхронизации в Java. Быстрее бывает только полное отстуствие синхронизации. Более того: в режиме чтения, который используется в примере, скорость доступа к volatile переменной практически не отличается от скорости доступа к несинхронизированной переменной. Товарищ Allen Holub был здесь неправ, или его неправильно поняли.
2. Корректная работа данного когда под Java версии < 1.5 тоже не гарантируется :)
Подробнее можно почитать у Билла Пью
0
Хотелось бы добавить пару основных вариантов использования синглтона. В некоторых случаях Singleton используется для экономии ресурсов, а в некоторых для реального контроля количества инстансов объекта в системе. В первом случае система проглотит неумелую реализацию без особых проблем, например если синглтон, являющийся фабрикой для создания объектов другого типа, создастся в каждом класслоадере, скорее всего это не будет критической проблемой, кроме конечно проблемы "чистого" решения с точки зрения оптимизации. Если речь идет о контроле объектов, например, конфигурационные параметры системы, которые могут динамически обновляться, то тут конечно грамотная реализация очень важна. Плюс если приложение кластерное, к вариантам реализации синглтона добавляются такие как, per cluster basis или per node basis, что опять же зависит от требований к классу. Вообщем есть о чем подумать на досуге, если вдруг обнаружилось, что класс можно реализовать синглтоном.
0
Вот ещё хорошая статья (да и вообще сайт хороший) на эту тему :)
0
Отличная статья! Но есть ещё один способ реализации синглетона - вызовы можно обрабатывать в одной нитке, скажем в Event Dispath Thread. Если запрос к синглетону идет из другой нити, его можно обработать, скажем, используя SwingUtilities.invkoeAndWait(...).
Такое решение подходит, когда _почи_ все вызовы идут в одном потоке.
Такое решение подходит, когда _почи_ все вызовы идут в одном потоке.
0
Неплохая вообщем-то статья, но растянутая, и слишком много как мне кажется уделено времени реализация однопоточности, когда чаще всего все-таки Singleton реализуются в многопоточности(иначе смысла большого нету использоваться этот паттерн). Хотелось бы увидеть еще другие паттерны, более сложные, и но не менее востребованные - фабрика, мосты, накопитель и т.д.
P.S. давно хотел написать пару статень по java. плюс пару статей по сертификации у Sun, если кому интересно, но пока к сожалению не могу.
P.S.S. интересный 5-ый вариант реализации, как-то не пользовался таким, обычно просто использовал синхранизацию на get методе, возьму на вооружение
P.S. давно хотел написать пару статень по java. плюс пару статей по сертификации у Sun, если кому интересно, но пока к сожалению не могу.
P.S.S. интересный 5-ый вариант реализации, как-то не пользовался таким, обычно просто использовал синхранизацию на get методе, возьму на вооружение
-1
Однопоточность обсуждается в одном варианте и одномн абзаце. Куда уж короче.
PS использовать синхронизацию на get() не имееет никакого смысла. Пора менять концепцию=)
PSS но, всеравно спасибо за позитивно-конструктивный комментарий
PS использовать синхронизацию на get() не имееет никакого смысла. Пора менять концепцию=)
PSS но, всеравно спасибо за позитивно-конструктивный комментарий
0
помойму вы сами себе противоречите, почему же не имеет смысла использовать сихнхронизацию на get ? Если у вас в 4А-ом примере используется сихронизация именно на get методе. Хотя конечно реализация 4Б-ым вариантом намного логичней. Реализация 1,2,3 фактически одно и тоже, и расматривает однопоточные решения. Различаются только способом создания объекта, и возможности обработки исключения на этапе инициализации объета или конструктора.
0
варианты 2,3 работают в многопоточной среде и не используют синхронизацию
0
Да ладно )) я вам могу как минимум привести 2-3 примера где вариант 2,3 не будет работать в многопоточной среде, и скорее всего выволется по exception'у. К примеру один поток запускает этот класс для инициализации, и тут вдруг срабатывает FullGC, все объекты и потоки переходят опять в состояние Runnable, и после этого JVM выбирает потом которые первый пойдет на выполнения, и нету гарантии что первый потом пойдет именно тот который был до FullGC. Дальше, если инициализация объекта достаточно затратное время -допустим коннект к базе данных, или еще что-нибудь. То я вас уверяю что без сихнронизации один поток скорее всего получит null в ответ, или выволиться StaticInitializationException. Причем еще такая реализация без сихнронизации может сильно отличаться в разных средах допустим на Solaris или Windows
0
я не понял вашего примера, но могу смело вам сказать, что вы не правы. В вариантах 2,3 объект инициализируется класслоадером, поэтому null никто не получит.
И уж точно непричем здесь Solaris и Windows=) Я согласен, что есть некороые различия в виртуальных машинах, но не на таком уровне.
И уж точно непричем здесь Solaris и Windows=) Я согласен, что есть некороые различия в виртуальных машинах, но не на таком уровне.
0
просто я разрабатываю системы реального времени со сверх большой нагрузкой, и каких только "не может быть" у нас не было, и каких разниц только в реализациях и поведения Solaris, Linux не было.
А системы отличаются очень сильно. К примеру Windows закрывает сокеты сразу же, а solaris вообще не закрывает сокеты, а переводит их в состояние TIME_WAIT(и таких примеров куча).
По поводу примеру, какой смысл надеятся на правильнную реализацию static class loader при многопоточном режиме ? я почти уверен что можно сэмулировать StaticInitializationException при подходве 2-3 в многопоточном обращении к объекту.
А системы отличаются очень сильно. К примеру Windows закрывает сокеты сразу же, а solaris вообще не закрывает сокеты, а переводит их в состояние TIME_WAIT(и таких примеров куча).
По поводу примеру, какой смысл надеятся на правильнную реализацию static class loader при многопоточном режиме ? я почти уверен что можно сэмулировать StaticInitializationException при подходве 2-3 в многопоточном обращении к объекту.
0
Если уж вы разарабатываете "системы реального времени со сверх большой нагрузкой", то должны занть цену синхронизации.
0
Цена синхронизации конечно важна, но намного важней чтоб не нарушалась целостность данных при многопоточной работе.
Мне не очень понравился пятый пример, все не мог понять чем. Нашел на javaworld.com, плюс на ibm.com, и я нашел объяснения - того что мне не нравится.
1) то что в 5-ом примере используете двойную проверку - это хорошо, если бы ее не было внутри сихнронизованной секции, это бы вообще работало не корректно и не был даже синглтон.
2) чем плох все-таки 5-ый пример в отличии от синхронизации именно метода getInstance(), вот что пишет ibm:
The theory behind double-checked locking is perfect. Unfortunately, reality is entirely different. The problem with double-checked locking is that there is no guarantee it will work on single or multi-processor machines.
The issue of the failure of double-checked locking is not due to implementation bugs in JVMs but to the current Java platform memory model. The memory model allows what is known as "out-of-order writes" and is a prime reason why this idiom fails.
Как раз что и я и говорил - при работе на реальных JVM в исключительных ситуациях.
К примеру вот такой вариант будет работать всегда:
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
Singleton inst = instance; //2
if (inst == null)
{
synchronized(Singleton.class) { //3
//inst = new Singleton(); //4
instance = new Singleton();
}
//instance = inst; //5
}
}
}
return instance;
}
Большая часть инфы и пример взят от сюда:
http://www.ibm.com/developerworks/library/j-dcl.html
Так же эту ситауацию еще расматривают тут
http://www.javaworld.com/jw-01-2001/jw-0112-singleton.html?page=6
Думаю на это дискуссия закончилась ) я не мог точно объяснить почему это плохо, теперь объяснение есть, поэтому я немного не в ту степь пошел при возникшем споре.
Мне не очень понравился пятый пример, все не мог понять чем. Нашел на javaworld.com, плюс на ibm.com, и я нашел объяснения - того что мне не нравится.
1) то что в 5-ом примере используете двойную проверку - это хорошо, если бы ее не было внутри сихнронизованной секции, это бы вообще работало не корректно и не был даже синглтон.
2) чем плох все-таки 5-ый пример в отличии от синхронизации именно метода getInstance(), вот что пишет ibm:
The theory behind double-checked locking is perfect. Unfortunately, reality is entirely different. The problem with double-checked locking is that there is no guarantee it will work on single or multi-processor machines.
The issue of the failure of double-checked locking is not due to implementation bugs in JVMs but to the current Java platform memory model. The memory model allows what is known as "out-of-order writes" and is a prime reason why this idiom fails.
Как раз что и я и говорил - при работе на реальных JVM в исключительных ситуациях.
К примеру вот такой вариант будет работать всегда:
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
Singleton inst = instance; //2
if (inst == null)
{
synchronized(Singleton.class) { //3
//inst = new Singleton(); //4
instance = new Singleton();
}
//instance = inst; //5
}
}
}
return instance;
}
Большая часть инфы и пример взят от сюда:
http://www.ibm.com/developerworks/library/j-dcl.html
Так же эту ситауацию еще расматривают тут
http://www.javaworld.com/jw-01-2001/jw-0112-singleton.html?page=6
Думаю на это дискуссия закончилась ) я не мог точно объяснить почему это плохо, теперь объяснение есть, поэтому я немного не в ту степь пошел при возникшем споре.
0
Чтож, очень обидно, что вы начинаете спор не прочитав статью внимательно. Как и ваше утверждение на тему многопоточности 2 и 3 варианов. Так и здесь, я написал, что Double-checked locking в своем оригинальном варианте не работает, но начиная с Java 5, починили модификатор volatile, и если его использовать, то Double-checked locking заработает. Жаль, что вы читаете по диагонали. Спор с вами мне стал не интересен, если хотите задавать вопросы - пожалуйста, но спорить с вами более я не буду.
0
2,3 вполне будут работать - classloader синхронизирует инициализацию класса. Иначе корректная инициализация классов в multithreaded программе была бы в принципе невозможна.
0
UFO just landed and posted this here
подозреваю, что если в последнем варианте synchronized блок вынести в отдельную процедуру, то все сработает.
0
неплохо. спасибо. ждем остальных паттернов. было бы интересно почитать и обсудить с народом потом.
0
Вот очень интересная статья на тему signleton:
www.javenue.info/post/83
Основная идея в том, что диспетчеризация вызова метода работает гораздо быстрее чем условный оператор (меньше тиков).
Говоря по простому: на реальном параллельном выполнении мы получаем огромную экономию процессорного времени.
Уверен, статья будет интересна абсолютно всем настоящим Java-программистам.
www.javenue.info/post/83
Основная идея в том, что диспетчеризация вызова метода работает гораздо быстрее чем условный оператор (меньше тиков).
Говоря по простому: на реальном параллельном выполнении мы получаем огромную экономию процессорного времени.
Уверен, статья будет интересна абсолютно всем настоящим Java-программистам.
0
UFO just landed and posted this here
Sign up to leave a comment.
Реализация Singleton в JAVA