Singleton Design Pattern

Singleton Design Pattern | Java

In software design, design patterns are tried-and-tested solutions to common problems. One such pattern is the Singleton Design Pattern. The Singleton pattern is a creational design pattern that ensures that a class has only one instance and provides a global point of access to that instance. It is widely used in Java and other programming languages to control the instantiation of a class and maintain a single instance throughout the application’s lifecycle. In this comprehensive guide, we will explore the Singleton Design Pattern in detail, discuss its implementation in Java, and provide real-world use cases where it can be applied effectively.

Understanding the Singleton Design Pattern

The Singleton pattern is a part of the Gang of Four (GoF) design patterns, which were introduced in the book “Design Patterns: Elements of Reusable Object-Oriented Software” by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. The Singleton pattern falls under the creational category of design patterns and is used to ensure that a class has only one instance and provides a global point of access to that instance.

Implementing Singleton Design Pattern | Java

Eager Initialization

In this approach, the Singleton instance is created when the class is loaded, ensuring that it’s always available. This is suitable when the instance is not resource-intensive to create and you want to ensure early initialization.

public class EagerSingleton 
{
    private static final EagerSingleton instance = new EagerSingleton();
    
    private EagerSingleton() { }
    
    public static EagerSingleton getInstance() 
    {
        return instance;
    }
}
EagerSingleton singleton = EagerSingleton.getInstance();

Use when the Singleton instance is lightweight and the application always needs it. It’s simple and doesn’t require additional synchronization.

Lazy Initialization ( Simple )

In this approach, the Singleton instance is created only when it’s first requested, which can save resources. However, it’s not thread-safe, so you might need to add synchronization if used in a multi-threaded environment.

public class LazySingleton 
{
    private static LazySingleton instance;
    
    private LazySingleton() { }
    
    public static LazySingleton getInstance() 
    {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
LazySingleton singleton = LazySingleton.getInstance();

Use when the Singleton instance is resource-intensive to create, and you’re not concerned about thread safety. It’s simple but not thread-safe.

Lazy Initialization ( Thread-Safe )

To make the lazy initialization approach thread-safe, you can use synchronized methods or a synchronized block inside the getInstance method. This ensures that only one instance is created even in a multi-threaded environment.

public class ThreadSafeSingleton 
{
    private static ThreadSafeSingleton instance;
    
    private ThreadSafeSingleton() { }
    
    public static synchronized ThreadSafeSingleton getInstance() 
    {
        if (instance == null) {
            instance = new ThreadSafeSingleton();
        }
        return instance;
    }
}
ThreadSafeSingleton singleton = ThreadSafeSingleton.getInstance();

Use when the Singleton instance is resource-intensive and you want to ensure thread safety. Be aware that it introduces some performance overhead due to synchronization.

Bill Pugh Singleton ( Lazy Initialization with inner Static Class )

This approach combines lazy initialization with thread-safety while avoiding the overhead of synchronization in every call to getInstance. It uses an inner static class to ensure thread-safe initialization.

public class BillPughSingleton 
{
    private BillPughSingleton() { }
    
    private static class SingletonHelper 
    {
        private static final BillPughSingleton instance = new BillPughSingleton();
    }
    
    public static BillPughSingleton getInstance() 
    {
        return SingletonHelper.instance;
    }
}
BillPughSingleton singleton = BillPughSingleton.getInstance();

Use when you want to ensure thread safety while keeping lazy initialization and avoiding synchronization overhead. This is a good choice in most scenarios and is recommended for most cases.

The Singleton Design Pattern is a powerful design pattern in software development, allowing you to ensure that a class has only one instance and providing a global point of access to that instance. It is particularly useful in scenarios where a single point of control or resource management is required. By implementing the Singleton pattern in Java, you can create efficient and organized code that is easy to maintain. Understanding when and how to apply the Singleton pattern is a valuable skill for any Java developer.

Leave a Reply

Your email address will not be published. Required fields are marked *