Skip to content

Singleton

Last Updated on 14/11/2020

Singleton Design Pattern Logo


Singleton is a creational design pattern which ensures that a class has only one instance and provides a global point to access it.

Introduction

Sometimes it makes sense in a system to have just only one instance of a certain class, e.g. configuration classes that read properties from a unique file or hardware access to send files to a printer.

Although Singleton seems to be one of the most popular patterns and yet, one of the easiest to implement, there are still certain features of the Java language like concurrency and serialisation, that may create some pitfalls in the pattern implementation, pitfalls we have to cover in order to rest assured that our Singleton instances are really singular.

That said, this post is not going to be “just yet another Singleton quick tutorial”, it is going to show how to safely write a piece of code that properly adheres to the pattern’s contract, both using a regular Java class and an alternative implementation using an enum.

Singleton Structure

We are going to create a class called SystemInfo which is going to be our Singleton class, then a simple client class called SystemClient to make use of it.

Below is the UML representation:

Simple Singleton UML Diagram

Some important considerations about the diagram:

  • SystemInfo is the class that both implement the pattern and fetches the needed system information the client classes need. Just by saying it has these two responsibilities we can identify a drawback in this pattern: it lacks a bit of cohesion.
  • SystemClient class is our client class in the representation, but it could be any client class in our systems.
  • Please note that the underlined attributes and methods are static, and for the pattern class, they are the only ones mandatory, the two remaining fields are just for demonstration purposes.

Implementation

Below are the Java resources which implement the pattern. As usual, some Javadoc, comments, getters, setters, constructors, and toString overwritten were omitted for readability purposes. Please refer to the GitHub repository for the full version of this code.

The First Version

Below is the first and easiest version of our Singleton pattern implementation, it has a lazy initialisation feature already:

package com.bgasparotto.designpatterns.singleton;

public final class SystemInfo {
	private static SystemInfo instance;

	private String systemName;
	private String javaVersion;

	private SystemInfo() {
		systemName = System.getProperty("os.name");
		javaVersion = System.getProperty("java.version");
	}

	public static SystemInfo getInstance() {
		if (instance == null) {
			instance = new SystemInfo();
		}

		return instance;
	}

	// Instance getters
}

This version of the code seems to do the job. It waits until the first call for initialising the singleton instance and ensures to return the same one on every call. Additionally, its constructor is private to force the client classes to call the getInstance method. It also makes the class impossible to extend because of the lack of accessible constructors, so we added the final modifier to clearly warn this behaviour to the programmer. However, it’s not quite what we want.

Concurrency: race condition

If our current SystemInfo class gets executed in a multi-thread application, the following can happen:

  1. Thread A invokes getInstance method;
  2. Thread A evaluates if (instance == null) to true;
  3. Thread A goes to the runnable state and Thread B goes to the running state;
  4. Thread B invokes getInstance method;
  5. Thread B also evaluates if (instance == null) to true;
  6. Thread B instantiates a SystemInfo object and assigns it to the instance static field;
  7. Thread B goes to the runnable state and Thread A takes place again;
  8. Thread A instantiates another SystemInfo object and replaces the current one in the instance static field;
  9. We now have two instances of SystemInfo, the class failed to be a singleton.

To solve that, we could simply make the getInstance method thread-safe by adding the synchronized keyword:

public static synchronized SystemInfo getInstance() {
	if (instance == null) {
		instance = new SystemInfo();
	}

	return instance;
}

But is it worthwhile synchronising a method and losing performance just because we wanted to gain some performance by lazy initialising our class? Probably not.

Another option is to create a private static class that also gets loaded upon its first invocation to hold our singleton instance, this way, we don’t lose performance because of the synchronisation and still get the lazy initialisation feature. Additionally, we can remove the instance field and the null check from SystemInfo:

private static class SystemInfoHolder {
	private static final SystemInfo INSTANCE = new SystemInfo();
}

public static SystemInfo getInstance() {
	return SystemInfoHolder.INSTANCE;
}

At this point we successfully made our class thread-safe.

The Second Version

Here comes the second and current version of our Singleton class:

package com.bgasparotto.designpatterns.singleton;

public final class SystemInfo {
	private String systemName;
	private String javaVersion;
	
	private static class SystemInfoHolder {
		private static final SystemInfo INSTANCE = new SystemInfo();
	}

	private SystemInfo() {
		systemName = System.getProperty("os.name");
		javaVersion = System.getProperty("java.version");
	}

	public static SystemInfo getInstance() {
		return SystemInfoHolder.INSTANCE;
	}

	// Instance getters
}

It currently ensures that just one lazy initialised unique instance can be obtained by the getInstance method in multi-thread environments. However, it can be broken again by the addition of two words in our class.

Serialisation

If we simply add the words implements Serializable in the class, it is not longer going to be guaranteed that only one instance will be always available:

public final class SystemInfo implements Serializable {
	// ...
}

This way, a second instance can be created when the serialisation mechanism deserialises the object through the default deserialisation process or through a custom readObject(ObjectInputStream in) implementation.

To solve this problem, we must provide a custom implementation for another serialisation mechanism’s method called readResolve() that returns an Object, which replaces the instance previously read from the stream during deserialisation process, making it eligible for garbage collection. The said custom implementation is simply going to ignore any read objects and return the singleton instance instead:

public final class SystemInfo implements Serializable {
	private Object readResolve() throws ObjectStreamException {
		return SystemInfoHolder.INSTANCE;
	}

	// ...
}

Additionally, we must define any instance variable that references another objects to be transient, in order to avoid the retrieval of the deserialised instance before readResolve is run:

private transient String systemName;
private transient String javaVersion;

Now, our singleton class guarantees that only and only one instance will be available in multi-thread environments and through serialisation.

The Third Version

Here comes the third version of our Singleton class:

package com.bgasparotto.designpatterns.singleton;

import java.io.ObjectStreamException;
import java.io.Serializable;

public final class SystemInfo implements Serializable {
	private static final long serialVersionUID = 2780033083469952344L;
	
	private transient String systemName;
	private transient String javaVersion;

	private static class SystemInfoHolder {
		private static final SystemInfo INSTANCE = new SystemInfo();
	}

	private SystemInfo() {
		systemName = System.getProperty("os.name");
		javaVersion = System.getProperty("java.version");
	}
	
	private Object readResolve() throws ObjectStreamException {
		return SystemInfoHolder.INSTANCE;
	}

	public static SystemInfo getInstance() {
		return SystemInfoHolder.INSTANCE;
	}

	// Instance getters
}

We are almost there! We just need to take care of one last thing.

Reflection

Although the basic reflection mechanism respects the class access modifiers, it can be by-passed the AccessibleObject.setAccessible(boolean flag) method in order to reflectively access private members.

The code snippet below reflectively obtains the private constructor and make it accessible, thus making it possible to manually instantiate the class:

public static void main(String[] args) throws Exception {
	// Obtains the singleton instance normally.
	SystemInfo firstInstance = SystemInfo.getInstance();

	// Make the private constructor accessible and obtains another instance.
	Constructor<SystemInfo> c = SystemInfo.class.getDeclaredConstructor();
	c.setAccessible(true);
	SystemInfo secondInstance = c.newInstance();

	// Both instances are different.
	System.out.println(firstInstance == secondInstance);
}

The above code will produce the following output:

false

To prevent that from happening, we simply move our initialisation code to an initialisation block or to the fields themselves like we are about to do, and make the private constructor throw an AssertionError if the INSTANCE is not null. This approach, unlike the null check presented at the beginning of this tutorial inside of the getInstance method, is thread-safe since it will always return false after the class is first loaded and the INSTANCE is initialised at the first time:

private transient String systemName = System.getProperty("os.name");
private transient String javaVersion = System.getProperty("java.version");

private SystemInfo() {
	if (SystemInfoHolder.INSTANCE != null) {
		throw new AssertionError("Can not instantiate.");
	}
}

The Final Version

Here it goes our final version of the singleton implementation, thread-safe and not prone to serialisation or reflection by-passing:

package com.bgasparotto.designpatterns.singleton;

import java.io.ObjectStreamException;
import java.io.Serializable;

public final class SystemInfo implements Serializable {
	private static final long serialVersionUID = 2780033083469952344L;
	
	private transient String systemName = System.getProperty("os.name");
	private transient String javaVersion = System.getProperty("java.version");

	private static class SystemInfoHolder {
		private static final SystemInfo INSTANCE = new SystemInfo();
	}

	private SystemInfo() {
		if (SystemInfoHolder.INSTANCE != null) {
			throw new AssertionError("Can not instantiate.");
		}
	}
	
	private Object readResolve() throws ObjectStreamException {
		return SystemInfoHolder.INSTANCE;
	}

	public static SystemInfo getInstance() {
		return SystemInfoHolder.INSTANCE;
	}

	public String getSystemName() {
		return systemName;
	}

	public String getJavaVersion() {
		return javaVersion;
	}
}

This is a valid Singleton implementation. However, we had to get our hands dirty to take care of a few possible pitfalls and that made our class more complicated than expected. Is there a simpler way to successfully implement a Singleton? Yes, there is.

The Singleton Enum

[…] a single-element enum type is the best way to implement a singleton.

– Joshua Bloch. Effective Java 2nd Edition p. 18.

An enum has what it takes to provide a valid Singleton implementation without any extra effort as seen in the previous sections, so unless you have a good reason to use classes to create singletons, use an enum instead.

A valid enum singleton that does exactly the same thing our previous class does can be represented like the following in UML:

Enum Singleton UML Diagram

And coded as the following:

package com.bgasparotto.designpatterns.singleton;

public enum SystemInfoEnum {
	INSTANCE;

	private String systemName = System.getProperty("os.name");
	private String javaVersion = System.getProperty("java.version");

	public String getSystemName() {
		return systemName;
	}

	public String getJavaVersion() {
		return javaVersion;
	}
}

Now if we get an instance of both implementations and invoke its methods, the result is exactly the same. It’s also important to note that the utilisation of both approaches is very similar:

package com.bgasparotto.designpatterns.singleton;

public class SystemClient {
	public static void main(String[] args) throws Exception {
		SystemInfo classInstance = SystemInfo.getInstance();
		SystemInfoEnum enumInstance = SystemInfoEnum.INSTANCE;
		
		System.out.println("Class: " + classInstance.getSystemName());
		System.out.println("Class: " + classInstance.getJavaVersion());
		
		System.out.println("Enum: " + enumInstance.getSystemName());
		System.out.println("Enum: " + enumInstance.getJavaVersion());
	}
}

Conclusion

We observed that a good Singleton’s implementation is not as easy to implement as we may have thought, because there are a few concerns about the language that have to be taken care of.

Those concerns involve thread-safety and code exploitation through reflection or serialisation, although it’s not difficult to get rid of these pitfalls, using an enum instead of a class makes the job very simpler and the code cleaner.

It is also important to note that we cannot subclass a valid singleton, so it is a drawback that must be take in consideration when deciding whether a singleton is that you really need to solve a problem. If you still need to subclass a singleton you are going to need to change the original singleton class before sub-classing it, for the reasons discussed before.

References

2 thoughts on “Singleton”

  1. Esmael Gonçalves Pains

    Congratulations man!
    Your article is very clear and didactic as well as being the most complete article I have ever seen about singletons.
    Very good (claps)

Leave a Reply

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