Pull to refresh

Comments 6

А где в первом примере лень? Обычный синглтон, ни разу не ленивый. getInstance() вызывает конструктор объекта.

Лень была бы если бы getInstance не запускала конструктор, а давала бы некоторый дополнительный объект, который содержал бы в себе все необходимые методы исходного объекта и в каждом методе сделана проверка того, а создан ли исходный объект, если нет то запускается его конструктор, а потом вызывается метод исходного объекта.

Да, это муторно, зато это будет настоящая лень.

Вроде в том и смысл, что пока не вызван getInstance() - объект не существует. Если не будет вызван ни разу - объект лениво никогда не создастся. Ваш вариант отличается только тем, что вызов конструктора перемещается в метод по сути проксика. Смысл это имеет только в одном случае - если мы допустим, что getInstance() вызывается в холостую и целевой объект нам не нужен, но зачем такое допускать? Если такое произойдет значит это облажался программист, пусть идет и исправляет.

В строчке `LazyInitializedSingleton instance = LazyInitializedSingleton.getInstance();` конструктор зачем-то вызывается, объект инициализируется, но при этом потребности в нём ещё нет. Потребность появляется только на следующей строчке. А могла бы и не возникнуть.

И что значит программист облажался? Почти всегда доподленно неизвестно, будет ли instance вообще использоваться хоть раз или нет. В приведенном коде очевидно, что instance нужен, но если бы instance использовался где то в другой функции, куда бы он передавался как аргумент, то зачастую очень сложно понять - а дейсвительно ли он нужен будет той функции, или в процессе исполнения функция обойдется без него?

Поэтому я и написал, что LazyInitializedSingleton вовсе не ленивый - его невозможно передать какой либо функции в качестве аргумента, не запустив конструктор. Невозможно положить его в хэш-мапу вместе с другими ленивыми объектами, чтобы дергать их оттуда по мере необходимости. Неизбежно потребуется создавать класс-обёртку, или что-то ещё городить, насколько фантазия позволит.

И конечно в реальности я бы не стал городить такой класс, где проверка на инициализацию сидит в каждом методе, гораздо проще сделать фабрику объекта с ленивой инициализацией. Но фабрика объекта и сам объект это разые типы данных. И даже если фабрика лениво инициализирует объект, то сам то объект всё равно не ленивый.

Делать весь метод getInstance() в ThreadSafeLazyInitializedSingleton synchronized все-таки несколько расточительно. Lock монитора не бесплатный, а нужен он ровно для одного вызова, который инициализирует переменную.
Еще, кажется, будут проблемы с тем, что поле instance не volatile, а значит может быть закэшировано тредом. Но тут не уверен, надо перечитать доку что там гарантирует JMM в этих случаях.

PS: не покритиковать ради, а из заботы о новичках. Люди могут потащить код из примеров в проекты и подложить себе мин замедленного действия. А так материал крутой и полезный.

Если всё под синхронизацией, то volatile не нужен, видимость и так корректна при всех вариациях и реордерингах.

Но весь этот подход избыточен: загрузка классов сама по себе ленива (и потокобезопасна). Достаточно не иметь других статических методов и полей в классе, и всё будет хорошо, просто и понятно: static final Singleton INSTANCE = new Singleton();

Sign up to leave a comment.