Design Patterns: Singleton

Singleton Design Pattern

Singleton is part of the Creational Design Patterns and one of the most commonly used. Although it has the simplest structure consisting of only one class, don’t get too comfortable. Despite its simplicity from the design perspective, there are quite a few things to consider in its implementation. In Java, the Singleton Pattern is often a controversial topic among developers regarding the application and its consequences.

Intent

Ensure that the class can only be instantiated once and provide a single global point of access to it.

Problem

On many occasions, there is a need to assure that a class will only have one instance. For example, logging, thread pools, window managers and driver objects.

But why do we have to implement a design pattern if we can just instantiate a new class only once in our code?

That is the question that most young developers ask themselves. It’s true that in simple programs you will have control over all the classes that are created (kind of). Now, imagine working on a project with thousand lines of code and collaborating with a team. You wouldn’t want someone (including you) breaking the application because he/she didn’t know that a class must not be instantiated twice. Using Singleton will assure that only one instance can be created. Besides, considering that the other developers are familiar with the pattern, the code will speak for itself, and no one will even try to create a second instance.

Solution

The goal is to ensure that only a single object can be created and that object must have a global point of access. And how do we do that? We make the class responsible for keeping track of
its sole instance. The class can assure that only one instance can be created and provide a way to access it.

We will also see alternative implementations and their outcomes later on, but for now, let’s start with the typical implementation.

Structure

Singleton Structure

Implementation

We said earlier that the Singleton Pattern has a straightforward structure. Let’s see why.

We only have one class. To implement the Singleton Pattern following the classic approach in Java, we use the following concepts:

  • A private static variable of the same class.
  • A private constructor to initiate the class.
  • A public method that returns the instance and acts as the global point of access.

Sounds simple right? Well, it is. However, there are quite a few ways to implement it, depending on your purpose.

-Eager Instantiation

public class EagerSingleton {
	
	private static final EagerSingleton INSTANCE = new EagerSingleton();
	
	// More variables
	
	private EagerSingleton(){}
	
	public static EagerSingleton getInstance(){
		return INSTANCE;
	}
	
	// More methods
}

In eager instantiation, the instance is initialized by the time the class is loaded. This can happen even if you don’t call the getInstance() method, as the class is loaded the moment you access it. For example, if you have another public static method doSomething() and call it, the instance will be initialized. This approach is thread-safe (see below for more).

-Lazy Instantiation

public class LazySingleton {
	
	private static LazySingleton INSTANCE = null;
	
	// More variables
	
	private LazySingleton(){
		System.out.println("LazySingleton created!");
	}
	
	public static LazySingleton getInstance(){
		if(INSTANCE == null){
			INSTANCE = new LazySingleton();
		}
		return INSTANCE;
	}

	// More methods
}

The object is instantiated lazily, meaning that it is created the first time we call the getInstance() method. Every other call after that will return the same instance. Even if you have another static public method and call it, the instance will not be initialized. The only reason to choose this approach is when you have a very large object or heavy construction code and also have other accessible static methods or fields that might be used before an instance is needed.  This implementation is not thread-safe.

-Thread safety

As we already saw, eagerly instantiated Singletons are thread safe. On the contrary, we have some problems with the lazy ones. Again you may see various ways to overcome that, but for me, the most concrete and efficient solution is Initialization-on-demand holder idiom. Don’t let the title frighten you. The implementation is still pretty simple.

public class ThreadSafeLazySingleton {
	
	// More variables
	
	private static class LazyHolder{
		static final ThreadSafeLazySingleton INSTANCE = new ThreadSafeLazySingleton();
	}
	
	public static ThreadSafeLazySingleton getInstance(){
		return LazyHolder.INSTANCE;
	}
	
	// More methods
}

I know we said one class, but here we used two. However, LazyHolder is an inner class, and it shouldn’t affect your structure. The difference with the classic LazySingleton above is that we let an inner class initialize the instance. Again we achieve the same functionality because the instance will not load even if we call a static method other than getInstance(). The instance will instantiate when the inner class loads. And that will happen only when we call the getInstance() method. By letting the inner class to handle the initialization of the instance we achieve thread safety. That’s because the class initialization phase is guaranteed by the Java Language Specification to be non-concurrent.

-Serializable

What if you need to save the state of the Singleton Object? We achieve that by making a class to implement the Serializable Interface. We can serialize the object to a byte stream and save it to a file and then we can deserialize it and get the object as it was before.

But in our case, this process breaks the singleton pattern. During deserialization, a new object is created. There is one way however to overcome this.

First, we provide the implementation of the readResolve() method.  As the deserialization process runs the method, we specify that the same instance must be kept.

But this is not enough. According to Joshua Bloch, in his well-known book Effective Java 2nd Edition (must read), the SerializedSingleton pattern is not attack-proof. On Item 77, he points out that all the fields must be declared transient in order to secure the pattern.

import java.io.Serializable;

public class SerializedSingleton implements Serializable{
	
	private static SerializedSingleton INSTANCE = new SerializedSingleton();
	
	// Any other field must be transient!
	
	private SerializedSingleton(){}
	
	public static SerializedSingleton getInstance(){
		return INSTANCE;
	}
	
	protected Object readResolve() {
	    return getInstance();
	}
	
	// More methods
}

Enum: The best Solution

What if there is a way to have everything in a few lines of code?

Joshua Bloch, once again, presented in Effective Java 2nd Edition, the use of an enum Singleton.

public enum EnumSingleton {
	
	INSTANCE;
	
	// More variables
	
	public void doSomething(){}
	
	// More methods
}

Enum Singleton acts like the EagerSingleton we saw above, and in addition is thread-safeserializable and is secure even when someone uses reflection. That means that you don’t have to implement anything else to achieve that.

You can call the EnumSingleton as you would do with any other class.

public static void main(String[] args){
	EnumSingleton.INSTANCE.doSomething();	
}

Outcomes

Using the Singleton Pattern will assure the existence of only one instance of the desired class. Although many attacks can be made to break the pattern, if used correctly it can overcome them and deliver its promise.

Nevertheless, many programmers vote against Singletons. The main reason is that it can be easily abused. A Singleton acts more or less as a global variable. And that’s rarely a good thing. You hide the dependencies of your application in your code and can inherently cause tight coupling. They also violate the single responsibility principle by the fact that except their purpose as a class, they also control their lifetime. All these can easily make it very difficult to test and to maintain.

Personally, I am not against the use of the Singleton Design Pattern. However, I do believe that it must be utilized only on particular occasions.

One comment

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.