The Singleton design pattern restricts the instantiation of a class, ensuring that only one instance of the class exists within the Java Virtual Machine (JVM). A Singleton class provides a global access point through which the single instance of the class can be accessed.
The Singleton design pattern is commonly used for logging, database driver objects, caching, configuration management, and thread pools. It is also used by several other design patterns, such as Abstract Factory, Builder, Prototype, and Facade.
To implement the Singleton Design Pattern, the following principles should be followed:
Private constructor – Prevents other classes from creating new instances of the class.
Private static instance reference – Holds the single instance of the class and prevents external modification.
Public static method – Provides a global access point to retrieve the Singleton instance.
Below are the different approaches for implementing the Singleton design pattern.
-
Eager initialization
In eager initialization, the Singleton instance is created when the class is loaded into memory. This is the simplest way to implement the Singleton design pattern. However, it has one drawback: the instance is created even if the client application never uses it, which may result in unnecessary memory usage.public class EagerInitializer{ private static final EagerInitializer instance = new EagerInitializer(); //private constructor to avoid client applications to use constructor. private EagerInitializer(){ } public static EagerInitializer getInstance(){ return instance; } }
If your Singleton class does not consume many resources, eager initialization is a suitable approach. However, in most real-world scenarios, Singleton classes are used to manage resource-intensive objects such as file systems, database connections, or configuration managers. In such cases, it is better to delay the creation of the instance until the client invokes the
getInstance() method.Another limitation of eager initialization is that it does not provide flexibility for handling exceptions that may occur during instance creation.
-
Static block initialization
The static block initialization approach is similar to eager initialization, except that the Singleton instance is created inside a static initialization block. This approach provides the flexibility to handle exceptions that may occur during instance creation.public class StaticInitializer { private static StaticInitializer instance ; //private constructor to avoid client applications to use constructor. private StaticInitializer() { } static { try { instance = new StaticInitializer(); } catch(Exception e) { throw new RuntimeException("Exception in static block"); } } public static StaticInitializer getInstance() { return instance; } }
Both eager initialization and static block initialization create the Singleton instance before it is actually needed. In many cases, this is not considered a best practice because the instance is created even if it is never used. In the following sections, we'll explore how to implement a Singleton class that supports lazy initialization.
-
Lazy Initialization
The lazy initialization approach creates the Singleton instance only when it is requested through the global access method (getInstance()). This ensures that the instance is created only when it is actually needed.Below is a sample implementation of the Singleton design pattern using the lazy initialization approach.
public class LazyInitializer{ private static LazyInitializer instance; //private constructor to avoid client applications to use constructor. private LazyInitializer(){ } public static LazyInitializer getInstance(){ if(instance == null){ instance = new LazyInitializer(); } return instance; } }
The above implementation works well in a single-threaded environment. However, in a multithreaded environment, it can cause issues if multiple threads enter the
if block simultaneously. In such a scenario, multiple instances of the Singleton class may be created, violating the Singleton design pattern and causing different threads to obtain different instances.In the next section, we'll explore different approaches for implementing a thread-safe Singleton class.
-
Thread Safe Singleton
The simplest way to make a Singleton class thread-safe is to synchronize the global access method (getInstance()). This ensures that only one thread can execute the method at a time, preventing multiple instances from being created concurrently.A typical implementation of this approach is shown below.
public class ThreadSafe{ private static ThreadSafe instance ; //private constructor to avoid client applications to use constructor. private ThreadSafe(){ } public static synchronized ThreadSafe getInstance(){ if(instance == null){ instance = new ThreadSafe(); } return instance; } }
The above implementation is thread-safe and works correctly. However, it can reduce performance because every call to the
getInstance() method requires synchronization, even after the Singleton instance has already been created. In practice, synchronization is only needed when the instance is created for the first time.To avoid this unnecessary synchronization overhead, the Double-Checked Locking pattern is used. In this approach, the instance is checked before entering the synchronized block and checked again inside the synchronized block. This ensures that synchronization occurs only during the initial creation of the Singleton instance while maintaining thread safety.
The following code snippet demonstrates the Double-Checked Locking implementation.
public static ThreadSafe getInstance(){
synchonized(ThreadSafe.class){
return instance;
A common real-world example of the Singleton design pattern is a
ConnectionFactory class. This class is implemented as a Singleton and contains the database connection configuration along with methods for creating database connections.The reason for making the ConnectionFactory class a Singleton is that only one instance of the factory is required throughout the application. This single factory instance can then be used to create multiple database Connection objects whenever needed—one factory, many connections.
catch (ClassNotFoundException e) {
catch (SQLException e) {
Thank you for visiting blog..
Hello Sir,
ReplyDeleteThanks for such wonderful articles.
It helped me a lot.
I have one doubt over here.
public class LazyInitializer{
private static final LazyInitializer instance = null;
//private constructor to avoid client applications to use constructor.
private LazyInitializer(){
}
public static LazyInitializer getInstance(){
if(instance == null){
instance = new LazyInitializer();
}
return instance;
}
}
In above example
instance is declared as static final.
And we can assign value to static final variable either at the line of declaration or in the static block.
But here you are assigning value to static variable in getInstance() method.
As per my knowledge it will give compile time error.
Can you please clear my doubt?
Thanks in Advance.
Regards,
Sagar
Thanks sagar...I corrected it.
DeleteReally nice article and well explained. But this is for single threaded applications. So what about multiple thread application. I found a really great explanation and solution there.
DeleteNice Tutorial Anil, with real world example. it easy to understand for newbie.
ReplyDeleteHow to restrict the object creation in java using singleton please refer this click here
ReplyDeleteGood explanation Anil !!
ReplyDelete"Great blog created by you. I read your blog, its best and useful information. You have done a great work. Super blogging and keep it up.php jobs in hyderabad.
ReplyDelete"
Great Blog Anil,its really helps lot .
ReplyDeleteWell explained . Great article on singleton pattern . There is also good singleton pattern example visit Singleton class example
ReplyDelete