In this article we will look into singleton design pattern in java and try to explore different ways to create singleton and some of its best practices. And also look how to break singleton.
Introduction
Singleton design pattern is creational design pattern this is used to ensure that a class has only one instance and provides a global point of access to that instance in throughout application.
this pattern is use usually used where we want to restricts the instantiation of a class and ensures that only one instance of the class exists in the Java Virtual Machine.
What is the purpose of singleton pattern
Singleton design pattern is use full where single instance makes more sense instead of multiple objects to achieve the objective is an applicable. Typical examples include logging systems, database connection managers, caches, and thread pools, among others.
Singleton Pattern Principles
- Single instance per JVM
- Compulsory private constructor, to restrict object creation.
- Must provide global access to create instance.
Different Implementation
To provide implementation of singleton design pattern, we have different approach. But all approach has to follow some common concept that is
- Private Constructor
- Private Static member variable
- Public Static method to provide global access to the instance.
Lest discuss different ways to implement the singleton class.
- Eager ways initialization
This is the one of simplest ways to create the singleton where the instance of singleton class is created at the time of class.
public class Singleton { // Private Static member variable, where object created when class is loaded private static Singleton instance = new Singleton(); //Private constructor private Singleton(){ } // Public Static method to provide global access to the instance. public static Singleton getInstance(){ return instance; } }
- Lazy ways Initialization
In the case of the lazy initialization approach, the object of the class is created when the getInstance() method is called. Let’s have a look at the code to understand this.
public class Singleton { //private static variable of same class private static Singleton theInstance = null; //private constructor private Singleton(){ } //public static method to get the singleton object when required public static Singleton getInstance(){ if (theInstance == null){ theInstance = new Singleton(); } return theInstance; } }
- Static block initialization
In this case, the Singleton object is created inside a static block and at the time of class loading into the JVM memory and also provide the ways to of exception-handling mechanism inside the static block.
public class Singleton { //Private Static member variable private static Singleton theInstance = null; //static block to initialize theInstance variable using constructor call static { try{ theInstance = new Singleton(); }catch (Exception exception){ System.out.println("Exception occurred while creating the instance "+exception); } } //Private Constructor private Singleton(){ } //Public Static method to provide global access to the instance public static Singleton getInstance(){ return theInstance; } }
- Thread Safe Singleton
All the above ways are not sufficient for the multi-threaded environment because without proper access to the critical resource, multiple threads can be inside the if block at the same time and they may create multiple objects. So, it will violate the rule of the Singleton design pattern.
To overcome this problem, we will create singleton class.
A simple way to create a thread-safe singleton class is to make the global access method synchronized so that only one thread can execute this method at a time.
public class Singleton { private static Singleton instance = null; //Private Static member variable private Singleton(){} //Private Constructor //Public Static method to provide global access to the instance public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
This approach guarantees us that only one instance will be created at any given point in time inside the memory. But in this approach, there is some problem, as we are using synchronize keyword with the getInstance(), this reduced the overall performance.
To avoid this extra overhead every time, double-checked locking principle is used. In this we are only using critical section synchronized block inside the if condition with an additional check to ensure that only one instance of a singleton class is created.
public class Singleton { //Private Static member variable private static Singleton theInstance = null; //Private Constructor private Singleton(){ } //thread safe public static method to get the singleton object when required public static Singleton getInstance(){ if (theInstance == null){ synchronized(Singleton.class){ //only one thread will be able to access this block. if (theInstance == null){ //once the object is created by one thread , for other threads this if condition will be false. theInstance = new Singleton(); } } } return theInstance; } }
Singleton Design Pattern Advantage
- Single Instance: The Singleton Pattern ensure that a class has only one instance per JVM. This can be useful when we want to avoided multiple instances, such as when managing shared resources or configurations.
- Global Access: Because a Singleton instance is globally accessible because of static method, this eliminates the need to pass objects’ instances or manage complex dependencies.
- Lazy Initialization: The Singleton design pattern supports lazy initialization, that help in instance creation only when it is accessed for the first time. This can improve performance.
- Thread Safety: The Singleton implementation can be made thread-safe, this allows multiple thread to access the instance without causing concurrency issues. This is very important in multi-threaded environment.
Singleton Design Pattern disadvantages
Singleton has several advantages, particularly in terms of thread safety and lazy initialization, some of the drawbacks to need to be consider:
- Global State: The Singleton pattern introduces a global state, any changes to the Singleton instance can affect whole application, this may create hidden bugs and error.
- Lifecycle of a Singleton Object: Managing the lifecycle of a Singleton, such as releasing resources or resetting the state, can be complicated, particularly in cases where the instance must be re-initialized.
- Limited Extensibility: Modifying the existing implementation can be challenging due to their restricted instantiation and global access, it can be difficult to extend or modify Singleton classes.
- Violates the Single Responsibility Principle: This principle states that every class should have a single task to do. Butin Singleton class, it will have two responsibility one to create an instance and other to do the actual task.
- Breaks the Open Closed Principle: This principle means “Open for Extension, Closed for Modification”. But Singleton class always returns its own instance and is never open for extension.
- Tight Coupling: Singleton can lead to tight coupling between classes. This can make it more difficult to modify or replace the Singleton implementation in the future.
1 thought on “Singleton design pattern in Java”