Singleton instance in java

Java Singleton Class

In object-oriented programming, a java singleton class is a class that can have only one object (an instance of the class) at a time. After the first time, if we try to instantiate the Java Singleton classes, the new variable also points to the first instance created. So whatever modifications we do to any variable inside the class through any instance, affects the variable of the single instance created and is visible if we access that variable through any variable of that class type defined.

Remember the key points while defining a class as a singleton class that is while designing a singleton class:

  1. Make a constructor private.
  2. Write a static method that has the return type object of this singleton class. Here, the concept of Lazy initialization is used to write this static method.

Purpose of Singleton Class

The primary purpose of a java Singleton class is to restrict the limit of the number of object creations to only one. This often ensures that there is access control to resources, for example, socket or database connection.

Memory space wastage does not occur with the use of the singleton class because it restricts instance creation. As the object creation will take place only once instead of creating it each time a new request is made.

We can use this single object repeatedly as per the requirements. This is the reason why multi-threaded and database applications mostly make use of the Singleton pattern in Java for caching, logging, thread pooling, configuration settings, and much more.

For example, there is a license with us, and we have only one database connection or suppose our JDBC driver does not allow us to do multithreading, then the Singleton class comes into the picture and makes sure that at a time, only a single connection or a single thread can access the connection.

How to Design/Create a Singleton Class in Java?

To create a singleton class, we must follow the steps, given below:

1. Ensure that only one instance of the class exists.

2. Provide global access to that instance by

  • Declaring all constructors of the class to be private.
  • Providing a static method that returns a reference to the instance. The lazy initialization concept is used to write the static methods.
  • The instance is stored as a private static variable.
Читайте также:  Css selectors tag with class

Example of singleton classes is Runtime class, Action Servlet, and Service Locator. Private constructors and factory methods are also an example of the singleton class.

Difference between Normal Class and Singleton Class

We can distinguish a Singleton class from the usual classes with respect to the process of instantiating the object of the class. To instantiate a normal class, we use a java constructor. On the other hand, to instantiate a singleton class, we use the getInstance() method.

The other difference is that a normal class vanishes at the end of the lifecycle of the application while the singleton class does not destroy with the completion of an application.

Forms of Singleton Class Pattern

There are two forms of singleton design patterns, which are:

  • Early Instantiation: The object creation takes place at the load time.
  • Lazy Instantiation: The object creation is done according to the requirement.

Implementation: Let us briefly how the singleton class varies from the normal class in java. Here the difference is in terms of instantiation as for normal class we use a constructor, whereas for singleton class we use the getInstance() method which we will be peeking out in example 1 as depicted below. In general, in order to avoid confusion, we may also use the class name as the method name while defining this method which will be depicted in example 2 below as follows.

Java

Hashcode of x is 558638686 Hashcode of y is 558638686 Hashcode of z is 558638686 Three objects point to the same memory location on the heap i.e, to the same object

Output Explanation:

Singleton class

In a singleton class, when we first-time call the getInstance() method, it creates an object of the class with the name single_instance and returns it to the variable. Since single_instance is static, it is changed from null to some object. Next time, if we try to call the getInstance() method since single_instance is not null, it is returned to the variable, instead of instantiating the Singleton class again. This part is done by if condition.

In the main class, we instantiate the singleton class with 3 objects x, y, and z by calling the static method getInstance(). But actually, after the creation of object x, variables y and z are pointed to object x as shown in the diagram. Hence, if we change the variables of object x, that is reflected when we access the variables of objects y and z. Also if we change the variables of object z, that is reflected when we access the variables of objects x and y.

Читайте также:  Java join не работает

Now we are done with covering all aspects of example 1 and have implemented the same, now we will be implementing the Singleton class with the method name as that of the class name.

Источник

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

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

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

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

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

1 Static field

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

2 Enum Singleton

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

+ Остроумно
+ Сериализация из коробки
+ Потокобезопасность из коробки
+ Возможность использования 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’ом автору, такой случай вопросизвести не удалось.

Читайте также:  Running python script as root

Наконец, 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 классы?” 🙂

Источник

Оцените статью