Getinstance java что это
Перейти к содержимому

Getinstance java что это

  • автор:

Правильный Singleton в Java

Уверен, каждый из читателей, знает что такое шаблон проектирования “Singleton”, но не каждый знает как его программировать эффективно и правильно. Данная статья является попыткой агрегирования существующих знаний по этому вопросу.

Кроме того, можно рассматривать статью как продолжение замечательного исследования, публиковавшегося на Хабрахабре ранее.

Неленивый Singleton в Java

Автору известно два способа реализации шаблона с нормальной инициализацией.

1 Static field
public class Singleton

+ Простая и прозрачная реализация
+ Потокобезопасность
Не ленивая инициализация

2 Enum Singleton

По мнению Joshua Bloch’а это лучший способ реализации шаблона [1].

public enum Singleton

+ Остроумно
+ Сериализация из коробки
+ Потокобезопасность из коробки
+ Возможность использования EnumSet, EnumMap и т.д.
+ Поддержка switch
Не ленивая инициализация

Ленивый Singleton в Java

На момент написания статьи существует как минимум три корректных реализации шаблона Singleton с ленивой инициализацией на Java.

1 Synchronized Accessor
public class Singleton < private static Singleton instance; public static synchronized Singleton getInstance() < if (instance == null) < instance = new Singleton(); >return instance; > > 

+ Ленивая инициализация
Низкая производительность (критическая секция) в наиболее типичном доступе

2 Double Checked Locking & volatile
public class Singleton < private static volatile Singleton instance; public static Singleton getInstance() < Singleton localInstance = instance; if (localInstance == null) < synchronized (Singleton.class) < localInstance = instance; if (localInstance == null) < instance = localInstance = new Singleton(); >> > return localInstance; > > 

+ Ленивая инициализация
+ Высокая производительность
Поддерживается только с JDK 1.5 [5]

2.1 Почему не работает без volatile?

Проблема идиомы Double Checked Lock заключается в модели памяти Java, точнее в порядке создания объектов. Можно условно представить этот порядок следующими этапами [2, 3]:

Пусть мы создаем нового студента: Student s = new Student(), тогда

1) local_ptr = malloc(sizeof(Student)) // выделение памяти под сам объект;
2) s = local_ptr // инициализация указателя;
3) Student::ctor(s); // конструирование объекта (инициализация полей);

Таким образом, между вторым и третьим этапом возможна ситуация, при которой другой поток может получить и начать использовать (на основании условия, что указатель не нулевой) не полностью сконструированный объект. На самом деле, эта проблема была частично решена в JDK 1.5 [5], однако авторы JSR-133 [5] рекомендуют использовать voloatile для Double Cheсked Lock. Более того, их отношение к подобным вещам легко прослеживается из коментария к спецификации:

There exist a number of common but dubious coding idioms, such as the double-checked locking idiom, that are proposed to allow threads to communicate without synchronization. Almost all such idioms are invalid under the existing semantics, and are expected to remain invalid under the proposed semantics.

Таким образом, хотя проблема и решена, использовать Double Checked Lock без volatile крайне опасно. В некоторых случаях, зависящих от реализации JVM, операционной среды, планировщика и т.д., такой подход может не работать. Однако, серией опытов сопровождаемых просмотром ассемблерного кода, генерированного JIT’ом автору, такой случай вопросизвести не удалось.

Наконец, Double Checked Lock можно использовать без исключений с immutable объектами (String, Integer, Float, и т.д.).

3 On Demand Holder idiom
public class Singleton < public static class SingletonHolder < public static final Singleton HOLDER_INSTANCE = new Singleton(); >public static Singleton getInstance() < return SingletonHolder.HOLDER_INSTANCE; >> 

+ Ленивая инициализация
+ Высокая производительность
Невозможно использовать для не статических полей класса

Performance

Для сравнения производительности выше рассмотренных методов, была использована микро-бенчмарка [6], определяющая количество элементарных операций (инкремент поля) в секунду над Singleton объектом, из двух параллельных потоков.

Измерения производились на двухядерной машине Intel Core 2 Duo T7300 2GHz, 2Gb ram и Java HotSpot(TM) Client VM (build 17.0-b17). За единицу скора считается количество инкрементов (а следовательно и захватов объекта) в секунду * 100 000.

Client Server
Synchronized accessor 42,6 86,3
Double Checked Lock & volatile 179,8 202,4
On Demand Holder 181,6 202,7

Вывод: если правильно подобрать реализацию шаблона можно получить ускорение (speed up) от до .

Summary

Можно выделить следующие короткие советы по использованию того или иного подхода для реализации шаблона “Одиночка” [1].

1) Использовать нормальную (не ленивую) инициализацию везде где это возможно;
2) Для статических полей использовать On Demand Holder idom;
3) Для простых полей использовать Double Chedked Lock & volatile idom;
4) Во всех остальных случаях использовать Syncronized accessor;

Java Class Library & Singleton

Примечательно, что разработчики Java Class Library выбрали наиболее простой способ реализации шаблона — Syncronized Accessor. C одной стороны — это гарантия совместимости и правильной работы. С другой — это потеря процессорного времени на вход и выход из критической секции при каждом обращении.

Быстрый поиск grep’ом по исходникам дал понять, что таких мест в JCL очень много.

Возможно следующая статья будет “Что будет если в Java Class Library правильно написать все Singleton классы?” 🙂

  • java
  • design patterns
  • singleton
  • double checked lock

Одиночка на Java

Одиночка

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

Одиночка имеет такие же преимущества и недостатки, что и глобальные переменные. Его невероятно удобно использовать, но он нарушает модульность вашего кода.

Вы не сможете просто взять и использовать класс, зависящий от одиночки в другой программе. Для этого придётся эмулировать присутствие одиночки и там. Чаще всего эта проблема проявляется при написании юнит-тестов.

Java. Шаблон Singleton

Шаблон не является частью языка Java, это рекомендация умных программистов для создания эффективных решений во время разработки сложных проектов.

Синглтон (singleton) это класс, у которого экземпляр создаётся только один раз. Хорошим примером такого поведения служит файловая система, система работы с видео и т.д. В Android можно привести примеры с классами OkHttpClient, Retrofit, Gson, SharedPreferences. Для реализации синглтона нужно создать закрытый конструктор и открытый статический член, который и позволяет получить доступ к единственному экземпляру класса. Например, так.

 public class Single < public static final Single INSTANCE = new Single(); private Single()<>public void someMethod() < Log.i("Log", "I am someMethod"); >> 

Закрытый конструктор вызывается один раз для инициализации поля INSTANCE. Открытых конструктор у класса нет, поэтому после инициализации класса будет существовать только один экземпляр Single.

Существует другой вариант, когда вместо открытого статического поля создаётся открытый статический метод, а поле становится закрытым.

 public class Single < private static final Single INSTANCE = new Single(); private Single()<>public void someMethod() < Log.i("Log", "I am a someMethod"); >public static Single getInstance() < return INSTANCE; >> 

Второй способ удобен тем, что вы можете позже отказаться от синглтона, но вам не придётся сильно переписывать код.

Позже был придуман третий вариант с использованием enum.

Синглетон (Singleton) — Java: Объектно-ориентированный дизайн

Синглетон это широкоизвестный шаблон проектирования используемый в том случае, когда нужно ограничить класс созданием ровно одного объекта. Реализация этого шаблона базируется на том, что конструктор делается приватным. Объект такого класса можно получить только через статический метод getInstance() .

public class Singleton  // Инстанс класса private static Singleton instance; // Приватный конструктор private Singleton()  > public static Singleton getInstance()  if (instance == null)  instance = new Singleton(); > return instance; > // Другие методы класса > Singleton::getInstance(); 

В этом коде, объект класса хранится в приватном статическом свойстве instance . Получить этот объект можно только с помощью статического метода getInstance() , который создает объект в случае необходимости. Таким образом достигается условие наличия ровно одного объекта этого класса на запущенное приложение.

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

  • Классы начинают неявно зависеть от синглетона, который используется в коде напрямую.
  • Любая часть приложения в любой момент времени может изменить синглетон, что может привести к неожиданным последствиям и сложностям в отладке.
  • Обеспечение потокобезопасности синглетона в многопоточных приложениях может стать проблемой. Плюс это негативно влияет на производительность.

Кроме того, даже там где изначально казалось что нужен ровно один объект, обычно оказывается что неплохо бы иметь возможность создавать несколько разных объектов, например в целях тестирования. Разные тесты могут тестировать разные ситуации, в которых нужны по-разному сконфигурированные объекты. Синглетоны делают такое тестирование невозможным.

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *