Singleton Design Pattern

Motivation

Sometimes it's important to have only one instance for a class. For example, in a system there should be only one window manager (or only a file system or only a print spooler). Usually singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.

The singleton pattern is one of the simplest design patterns: it involves only one class which is responsible to instantiate itself, to make sure it creates not more than one instance; in the same time it provides a global point of access to that instance. In this case the same instance can be used from everywhere, being impossible to invoke directly the constructor each time.

Intent

  • Ensure that only one instance of a class is created.

  • Provide a global point of access to the object.

Implementations:

Lazy instantiation | Non Thread Safe

This is very basic lazy instantiation implementation of the Singleton Design Pattern. The logic to construct the object is placed into getInstance() method so until this method is called, object of Singleton class would not be constructed. That's why this way of instantiation is known as lazy instantiation. The instantiation logic(instance = new Singleton()) is placed into null check(instance == null) block so object will only be constructed when getInstance() method will be invoked first time, in subsequent method calls previously constructed objected will be returned.

The bad thing about this implementation is that it's not thread safe and in multi-threaded environment there is possibility that two or more threads can access getInstance() method simultaneously and result in construction of multiple instance of Singleton class.

We should always avoid such implementation.

Lazy instantiation | Thread Safe

This is thread safe, lazy instantiation implementation of Singleton Design Pattern. Here getInstance() is synchronized hence making sure that in multi-threaded environment only single thread should be executing the method at a time and whichever thread gets access first will create the instance and same instance will be returned to other threads when those will call getInstance().

The bad thing about this implementation is that it's not good implementation in terms of performance. Actually we need synchronization only to make sure only one thread should be able to call object construction logic(instance = new Singleton()). Once object construction is done any number of threads can access the method getInstance() sequentially or parallely, all will get previously created instance. But this implementation snchronizes all the getInstance() calls every time and incurs performance cost as we know synchronization lowers the performance.

Lazy instantiation | Improved Thread Safety | Double Locking

This is thread safe, lazy instantiation, well performant implementation of Singleton Design Pattern using double locking mechanism.

Here instead of sychronizing getInstance() method, object construction logic is placed into synchronized block, sandwiched into null check logic(instance == null). This way of implementation will ensure synchronization happens only once when first time getInstance() method will be invoked, in all other cases, previously constructed instance would be returned hence synchronized block would not be executed again.

This implementation cab be problematic when Singleton instance is transferred over the network means if Singleton implements Serializable then while de-serializing a new instance would be created hence would result in having multiple Singleton instances.

To avoid multiple instances of Singleton class one should override readResolve() method.

Lazy instantiation | Thread Safety | Double Locking | Serializable

This is thread safe, lazy instantiation, well performant, serializable implementation of Singleton Design Pattern.

Here Singleton implements Serializable so we have overriden readResolve() method, hence while de-serializing this method will call getInstance() method to create/get the object, if object is already there then existing object would be returned or new one would be constructed.

Early instantiation

This is early instantiation implementation of the Singleton Design Pattern.

Here instance variable is made static and initialized with new Singleton() so when class will be loaded by class loader object would be constructed and can be accessed by any client by calling getInstance() method.

The difference between lazy and early instantiation is that, lazy instantiation defers object construction until it's needed very first time by any client while early instantiation ensures object is constructed as soon as class is loaded, irrespective of the fact whether instance is needed by any client or not at that point.

Pros

  • A class will always has a single instance

  • Global access point to the instance

  • Singleton object initialised only when it's requested for first time

Cons

  • Violates the Single Responsibility Principle

  • Difficult to unit test

  • Promotes tight coupling

  • Hides dependencies

Important Points

Multithreading

A special care should be taken when singleton has to be used in a multithreading application.

Serialization

When Singletons are implementing Serializable interface they have to implement readResolve method in order to avoid having 2 different objects.

Classloaders

If the Singleton class is loaded by 2 different class loaders we'll have 2 different classes, one for each class loader.

Global Access Point

Global Access Point is represented by the class name - The singleton instance is obtained using the class name. At the first view this is an easy way to access it, but it is not very flexible. If we need to replace the Singleton class, all the references in the code should be changed accordingly.