Singleton Design Pattern
Singleton design pattern is creational design pattern which enables you to ensure that the class has only a single instance, while providing a globally shared access point to this instance.
Principles
Singleton pattern ensure that only one instance of the class will present throughout the entire application.
Provide a global access point to access the instance of the class.
In a multi-threading environment it prevents multiple threads to create multiple instances simultaneously.
Restrict direct access to constructor using private constructor and force the client to use the access point.
When to use this pattern?
Singleton pattern is super useful in these scenarios.
When you want to use a object in multiple places of your application and the functionality of the object is constant over all the instances, then you can use this design pattern. For example, we use
logger
in many places of our application and creating multiple instance of logger and single instance serves the same.Use it when you want to give the client a single access point to the instance.
It is super useful in multithreading system place where multiple threads are simultaneously accessing and making changes in a class. It enables that only one thread can access the instance at a time which prevent from unwanted overrides by multiple threads.
It is also useful in making database connections as well. Think about a scenario where your application is making multiple database connection from multiple part of your application. This is inefficient to create multiple database connections. While you can create a single connection and make it globally accessible. Here using singleton pattern you can create single instance of database connection class and serve it globally.
Implementation
There are different variations and implementations of this pattern according to needs and scenarios. Here are some
1. Eager Initialization
In this method the instance of the singleton class is create on the time of application/program starts, independent of usage of it. Then this instance is exposed by a public function. This class constructor is kept private to restrict the client to create a instance of class from constructor.
public class EagerInitialization {
// create the instance when application starts
private static final EagerInitialization eagerInitialization = new EagerInitialization();
// private constructor so that application can not
// use this to create instance
private EagerInitialization(){}
// access point function to get the instance
public static EagerInitialization getInstance() {
return eagerInitialization;
}
}
The main drawback of this approach it creates the instance of the class even if the application is not using getInstance
method. In most of the cases, we use singleton classes are created for resources like Database connections, File system etc. If the class is not using so much resources then this method can be used. But we should avoid class instantiation until getInstance
method is called.
2. Lazy Initialization
Lazy initialization is a more dynamic type of eager initialization method of creating singleton instance. Here when application starts the instance of the singleton class is null
. When client request for the instance then only the instance is created. On each instance request the global access point checks if the instance is already created or not. If is available then returns it otherwise create new instance of the class.
public class LazyInitialization {
private static LazyInitialization lazyInitialization = null;
// private constructor so that application can not
// use this to create instance
private LazyInitialization(){}
// access point function to get the instance
public static LazyInitialization getInstance() {
if(lazyInitialization == null) {
lazyInitialization = new LazyInitialization();
}
return lazyInitialization;
}
}
But in a multithreaded environment multiple thread can be inside in the If
condition and multiple instance of the class which breaks the rule of singleton pattern. So it is not thread safe.
3. Thread Safe Singleton
The easiest way to create a thread safe singleton is to make the access point method synchronized
. This will ensure that only one thread can execute the method at a time.
public class ThreadSafeSingleton {
private static ThreadSafeSingleton threadSafeSingleton = null;
// private constructor so that application can not
// use this to create instance
private ThreadSafeSingleton(){}
// synchronized access point function to get the instance
public static synchronized ThreadSafeSingleton getInstance() {
if (threadSafeSingleton == null) {
threadSafeSingleton = new ThreadSafeSingleton();
}
return threadSafeSingleton;
}
}
4. Bill Pugh Singleton
When too many threads simultaneously access the class it causes issue. The issue occurred in Java prior to Java 5. So Bill Pugh came up with a approach of getting instance of the singleton class by a private inner statis class.
public class BillPughSingleton {
// private static inner class
private static class Helper {
private static final BillPughSingleton BILL_PUGH_SINGLETON_INSTANCE = new BillPughSingleton();
}
// private constructor so that application can not
// use this to create instance
private BillPughSingleton(){}
public static BillPughSingleton getInstance() {
return Helper.BILL_PUGH_SINGLETON_INSTANCE;
}
}
Then reason is that , when the class is loaded private inner statis class is not loaded. It is loaded then the application requires the instance of the class. This is a widely used approach of creating singleton class as it does not require the synchronized
keyword and also thread safe.
Others
This is the pattern which is used as the foundational pattern for other patterns.
Small overview of creating a basic singleton class.
Declare the instance variable of type of the class as private static and initial value will be
null
.Make the constructor private.
Create a public static method which returns the class instance variable which you declared earlier, but before that it checks if it is
null
then create the instance of it.
This pattern is useful in memory optimization as creating multiple instance taken more heap memory. Here we are creating only single instance and every object of the class pointing to it only.
Subscribe to my newsletter
Read articles from Surjendu Pal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by