GoF's 23 Design Patterns Explained and Demonstrated: (1) Singleton Pattern — Lazy Singleton and Eager Singleton

The Singleton pattern is defined as a pattern where a class has only one instance and the class can create that instance by itself. It is mainly used to solve the frequent creation and destruction of objects, while ensuring logical correctness — for example, only one Task Manager can be opened in Windows, avoiding the waste of memory resources from opening multiple Task Manager windows, or errors such as inconsistent content shown in different windows.

Code will be shared at https://github.com/NeilRen/DesignPatterns

Original This article is original, author: Ren Fei. Please cite the author and source when reposting.

What Is the Singleton Pattern

The Singleton pattern is defined as a pattern where a class has only one instance and the class can create that instance by itself. It is mainly used to solve the frequent creation and destruction of objects, while ensuring logical correctness — for example, only one Task Manager can be opened in Windows, avoiding the waste of memory resources from opening multiple Task Manager windows, or errors such as inconsistent content shown in different windows.

The Singleton pattern has 3 characteristics:

  1. A singleton class has only one instance object.

  2. That singleton object must be created by the singleton class itself.

  3. The singleton class provides an external global access point to access the singleton.

Implementing the Singleton Pattern

The Singleton pattern is one of the simplest design patterns. Normally, a regular class’s constructor is public, and external classes can generate multiple instances via new Constructor(). But if you make the class’s constructor private, external classes cannot call it and thus cannot generate multiple instances. At this point the class itself must define a static private instance and provide a static public function to create or obtain that static private instance.

Lazy Singleton

The characteristic of this pattern is that no singleton is generated when the class loads; the singleton is only created when the getInstance method is called for the first time. Code as follows:

package net.renfei.designpatterns.singleton;

/**
 * Lazy singleton pattern
 *
 * @author RenFei
 */
public class LazySingleton {
    /**
     * Ensure instance is synchronized across all threads
     */
    private static volatile LazySingleton instance = null;

    /**
     * Private constructor ensures external code cannot instantiate
     */
    private LazySingleton() {
    }
    /**
     * synchronized ensures thread safety
     */
    public static synchronized LazySingleton getInstance() {
        // Add synchronization before getInstance method
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

Eager Singleton

The characteristic of this pattern is that a singleton is created as soon as the class loads, ensuring the singleton already exists before getInstance is called.

package net.renfei.designpatterns.singleton;

/**
 * Eager singleton pattern
 *
 * @author RenFei
 */
public class HungrySingleton {
    /**
     * A singleton is created as soon as the class loads
     */
    private static final HungrySingleton instance = new HungrySingleton();

    /**
     * Private constructor ensures external code cannot instantiate
     */
    private HungrySingleton() {
    }
    public static HungrySingleton getInstance() {
        return instance;
    }
}

The lazy singleton saves resources, but the first call is a bit slower if it hasn’t been instantiated yet; the eager singleton is fast to use, but it runs the instantiation logic during initialization, making program startup slower, and it loads into memory whether or not it is needed, which wastes resources.

Application Scenarios of the Singleton Pattern

Having analyzed the structure and characteristics of the Singleton pattern, here are the characteristics of the scenarios where it typically applies.

When a certain class is required to produce only one object, such as the class monitor in a class, or each person’s ID number.

When an object needs to be shared. Since the Singleton pattern allows only one object, sharing it saves memory and speeds up access. Examples include configuration objects in web apps and database connection pools.

When a class needs to be instantiated frequently and the created objects are also destroyed frequently, such as thread pools and network connection pools in multithreading.