00:00

Singleton Design Pattern

The Singleton Design Pattern is one of the most commonly used design patterns in Java. It ensures that a class has only one object (instance) throughout the entire application and provides a global access point to that instance.

Why Do We Need the Singleton Pattern?

In many real-world scenarios, creating multiple objects of a class does not make sense. For example:

  • Database connection manager
  • Logging service
  • Configuration settings
  • Cache manager

If multiple objects are created for these cases, it can lead to:

  • Wasted memory
  • Data inconsistency
  • Performance issues

The Singleton pattern solves this problem by making sure that only one object exists.

Key Characteristics of Singleton Pattern

  • Only one instance of the class is created
  • Constructor is private
  • Provides a static method to get the instance
  • Instance is globally accessible

Basic Singleton Example (Lazy Initialization)

This is the simplest form of the Singleton pattern. The object is created only when it is needed.

    
    class Singleton {
    
        private static Singleton instance;
    
        private Singleton() {
            // private constructor
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    
    

How It Works

  • The constructor is private, so no one can create an object using new
  • The static method getInstance() checks if an instance exists
  • If not, it creates one and returns it
  • The same object is returned every time

Using the Singleton Class

    
    public class TestSingleton {
    
        public static void main(String[] args) {
    
            Singleton obj1 = Singleton.getInstance();
            Singleton obj2 = Singleton.getInstance();
    
            System.out.println(obj1 == obj2); // true
        }
    }
    
    

Both variables point to the same object, which confirms that only one instance exists.

Thread-Safe Singleton (Synchronized Method)

In a multi-threaded application, multiple threads can create multiple instances at the same time. To avoid this, we use synchronization.

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

This approach is thread-safe but can reduce performance because every call to getInstance() is synchronized.

Double-Checked Locking Singleton (Best Practice)

This version improves performance and ensures thread safety.

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

The instance is created only once and synchronization is used only when required.

Eager Initialization Singleton

In this approach, the object is created at the time of class loading.

    
    class Singleton {
    
        private static final Singleton instance = new Singleton();
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            return instance;
        }
    }
    
    

This is simple and thread-safe but may create the object even if it is never used.

Real-World Example: Logger Singleton

    
    class Logger {
    
        private static Logger logger;
    
        private Logger() {
        }
    
        public static Logger getLogger() {
            if (logger == null) {
                logger = new Logger();
            }
            return logger;
        }
    
        public void log(String message) {
            System.out.println("LOG: " + message);
        }
    }
    
    

This ensures that all parts of the application use the same logger instance.

Advantages of Singleton Pattern

  • Controlled access to a single instance
  • Saves memory
  • Easy to implement
  • Useful for shared resources

Disadvantages of Singleton Pattern

  • Can make unit testing difficult
  • Introduces global state
  • Can hide dependencies

When Should You Use Singleton?

  • When only one object is required across the application
  • When managing shared resources like database connections
  • When consistent configuration is needed

Conclusion

The Singleton Design Pattern is a simple yet powerful pattern used to control object creation in Java. When used correctly, it helps improve performance, maintain consistency, and manage shared resources effectively. However, it should be used carefully to avoid unnecessary complexity.