Java programming language logo

Singleton Design Pattern

The Singleton pattern ensures that a class has only one instance, and that sole instance is shared among all objects those want to use it.

This pattern can be used when we need guarantee only one instance exists from an object.

A Singleton class can not be instantiated directly because its constructor is private. The class has a private static field, which holds the reference to the only instance of the class. To get a reference to it, we need to call a method, usually it's called getInstance. This method gives back the same object every time from a static field. Remember, in Java, static variables cannot be elected for garbage collection while the class is loaded, therefore the same instance stays alive.

Singleton implementation is very easy. It stands only from one class, but can be implemented in different ways. Below there are three different versions.

Note: With multiple class loaders the Singleton pattern can be broken and results in multiple instances.

Singleton is a creational pattern.

Example 1 - The Lazily Created Version

In the lazily created version, the instantiation happens when the getInstance method get called at the first time. It checks whether the instance is null. At the first call it is, so a new instance is created and returned. At every further call, the instance won’t be null, and just gets returned.

This is the basic logic for the Singleton pattern in Java. Having an empty object without any benefit is not very useful. To make sense for its existing, let’s add a collection to it that stores some invaluable data. In this example, that would be a set of fruits. With the Singleton pattern, we can ensure there is one instance of this data exists. If a client does any modification on it, another client will get reference to the modified one.


package com.programcodex.designpatterns.singleton;

import java.util.HashSet;
import java.util.Set;

public class SingletonLazilyCreated {

    private static SingletonLazilyCreated instance;
    private Set<String> fruits;

    private SingletonLazilyCreated() {
        fruits = new HashSet<>();
        fruits.add("orange");
        fruits.add("apple");
        fruits.add("grape");
    }

    /**
     * It's not synchronized, Hopefully it won't cause any problem.
     */
    public static SingletonLazilyCreated getInstance() {
        if (instance == null) {
            instance = new SingletonLazilyCreated();
        }
        return instance;
    }

    public Set<String> getFruits() {
        return fruits;
    }

    @Override
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
}

However, there is a design flaw in above implementation. It’s not thread safe. What if the instantiation takes a longer time. For example, data collection needed from a slow database. Meanwhile the data creation happens, another thread will find the instance as null, so it will also create a new object. The solution is in the next example.

Example 2 - The Synchronized Version

In the synchronized version, the getInstance method has a different implementation. To ensure that only one thread could create a new instance, we have to use synchronization. If we made the getInstance method synchronized, that would make the threads waiting each other when multiple calls happen at the same time. However, synchronization needed only at the first call, not anymore, so it wouldn't be a good idea to make the whole method synchronized.

That’s why if the instance is null, then a synchronized block is executed. In this block, the instance checked against null again, and if it is still true, the new instance is created.

But why have to check the instance twice? Meanwhile the synchronized block is executed, a second thread could call the getInstance method. It will also find the instance as null and try to enter the synchronized block, but it has to wait for the first thread to finish with it. So when the first thread done, the instance already has a value. The second thread enters into the synchronized block, but if check won’t be true by this time, therefore the instantiation skipped. Any further call to this method won’t be concerned by the synchronization.

Finally, notice the volatile keyword at the instance field. It guarantees visibility of changes to variables across multiple threads.


package com.programcodex.designpatterns.singleton;

import java.util.HashSet;
import java.util.Set;

public class SingletonSync {

    /**
     * The volatile guarantees visibility of changes to variables
     * across multiple threads. 
     */
    private volatile static SingletonSync instance;
    private final Set<String> fruits;

    private SingletonSync() {
        fruits = new HashSet<>();
        fruits.add("orange");
        fruits.add("apple");
        fruits.add("grape");
    }

    /**
     * If the method would be synchronized
     * then it would slow down threads unnecessarily
     * because synchronization needed only at the beginning. 
     */
    public static SingletonSync getInstance() {
        if (instance == null) {
            synchronized (SingletonSync.class) {
                if (instance == null) {
                    instance = new SingletonSync();
                }
            }
        }
        return instance;
    }

    public Set<String> getFruits() {
        return fruits;
    }

    @Override
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
}

Example 3 - The Eagerly Created Version

In the eagerly created version the instance gets its value at declaration. So the getInstance method got simpler because no needed for synchronization nor null check. The static field gets its value only once when the class is invoked.

It seams to be a bright solution, but be aware of that in this version the instantiation happens every time the class is used regardless the instance is used or not. This should not cause a problem in a well designed software. It would be a design flaw, if the singleton class were needed, but not needed its instance variable. See this in the TestSingleton class below.


package com.programcodex.designpatterns.singleton;

import java.util.HashSet;
import java.util.Set;

public class SingletonEagerlyCreated {

    /**
     * This way neither synchronization nor null check
     * needed in the getInstance method.
     */
    private static final SingletonEagerlyCreated instance = 
            new SingletonEagerlyCreated();
    
    private final Set<String> fruits;
    
    public static String DESIGN_FLAW =
            "This should not be here or at least should be final.";

    private SingletonEagerlyCreated() {
        fruits = new HashSet<>();
        fruits.add("orange");
        fruits.add("apple");
        fruits.add("grape");
        System.out.println("SingletonEagerlyCreated() constructor is called...");
    }

    public static SingletonEagerlyCreated getInstance() {
        return instance;
    }

    public Set<String> getFruits() {
        return fruits;
    }

    @Override
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
}

And we are done. It’s time to run these things.


package com.programcodex.designpatterns.singleton;

import java.util.Set;

public class TestSingleton {

    public static void main(String[] args) {
        System.out.println("Lazily created singleton:\n");
        SingletonLazilyCreated stonLazily = SingletonLazilyCreated.getInstance();
        print(stonLazily.getFruits());

        System.out.println("Synchronized singleton:\n");
        SingletonSync stonSync = SingletonSync.getInstance();
        Set<String> fruits = stonSync.getFruits();
        print(fruits);
        
        System.out.println("Let's add two fruits to the collection, and remove the apple.");
        fruits.add("raspberry");
        fruits.add("strawberry");
        fruits.remove("apple");
        
        System.out.println("Get another instance.");
        System.out.println("Whether it contains the modification? Yes, it does:\n");

        stonSync = SingletonSync.getInstance();
        print(stonSync.getFruits());
        
        System.out.println("Eagerly created singleton:\n");
        System.out.println("We don't call the getInstance() method,\n"
                + "but the class is instantiated because a variable is used from the class:");
        System.out.println(SingletonEagerlyCreated.DESIGN_FLAW);      
    }

    private static void print(Set<String> set) {
        set.stream().forEach(System.out::println);
        System.out.println();
    }
}

The output of the above test class:

The Singleton Design Pattern