Table of Contents

About

The singleton pattern is a design pattern used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.

Singletons usually are used to provide a single point of access to a global service. It doesn't have to instantiate the object. It just has to provide access to the object. The object returned can be set by any means necessary.

Example

Database

Application uses database connection pooling, so one DB connection can be shared among many requests. The singleton is usually the object which manages this pool.

Instantiation

A singleton with parameters is NOT a singleton because you may have more object than one of them.

If you want your singleton to be initialized with some data, you may pass them after initialization (or via a builder pattern)

SingletonObj singleton = SingletonObj.getInstance();
singleton.init(paramA, paramB); // init the object with data

Anti-Pattern

Singletons are an anti-pattern. They have private constructor and they are then very hard to subclass and configure.

Implementation Type

Static (Language-specific)

You can implement singletons by using language-specific features, such as the static keyword for Java

Object

A singleton allows access to a single created instance that can be:

  • passed as a parameter to other methods,
  • treated as a normal object.
  • and therefore can implement interface

Object Implementation

From the less desirable to the most desirable solution.

Method Initialization

public class MethodInitializationSingleton {

    private static MethodInitializationSingleton singleton;

    private MethodInitializationSingleton() {
    }

    public static MethodInitializationSingleton getSingleton() {
        if (singleton == null) {
            singleton = new MethodInitializationSingleton();
        }

        return singleton;
    }

}

This implementation is not Thread-safe. If two threads, Thread 1 and Thread 2, call getInstance() at the same time, two instances can be created.

If Thread 1 is pre-empted just after it enters the if block and control is subsequently given to Thread 2.

Class initialization

Class initialization (ie Eager initialization) with a static initialization block in order to manage exception.

public class ClassInitializationSingleton {

    private static final ClassInitializationSingleton singleton;

    static {
        try {
            singleton = new ClassInitializationSingleton();
        } catch (Exception e) {
            throw new RuntimeException("An error occurred!", e);
        }
    }
    
    private ClassInitializationSingleton() {
    }

    public static ClassInitializationSingleton getSingleton() {
        return singleton;
    }

}
  • Class initialization is thread-safe because of the Java specification.
  • It is possible to instantiate more than one Singleton instance using Java reflections (by modifying the constructor to Accessible and calling it)

Synchronized Method Initialization

public class SynchronizedSingleton {
    
    private static SynchronizedSingleton singleton;

    private SynchronizedSingleton() {
    }

    public static synchronized SynchronizedSingleton getSingleton() {
        if (singleton == null) {
            singleton = new SynchronizedSingleton();
        }

        return singleton;
    }
    
}
  • Synchronized methods are quite costly.
  • It is possible to instantiate more than one Singleton instance using Java reflections (by modifying the constructor to Accessible and calling it)

Enumeration

In Java, Enumerations can contain method implementations and hence can be used to implement Singleton’s logic.

See Enum Singleton

Java

Documentation / Reference