5 ways to write a singleton and why you shouldn’t !

One Singleton to Rule ‘em All !

The singleton design pattern is one of the most inappropriately used patterns. Singletons are intended to be used when a class must have exactly one instance, no more, no less. Designers/ coders/ developers frequently use singletons in a misguided attempt to replace global variables. A singleton is, for all intents and purposes, a global variable.

In this article we will go from the most dumb down version of a singleton to an ironclad guaranteed implementation of a singleton that will not bow down to multiple instantiation, even in the face of sophisticated serialization or reflection attacks.

While implementing Singleton we have 2 options,
1. Early loading
2. Lazy loading

Lazy loading adds a bit overhead(lots of, to be honest) so use it only when you have a very large object or a heavy construction code AND also have other accessible static methods or fields that might be used before an instance is needed, then and only then you need to use lazy initialization. Otherwise choosing early loading is a good choice.


Early Loading Singleton

Things are less complicated and chances of making a mistake is relatively less in early loading as the object is created early on and served when requested.

public class Singleton {
private static final Singleton INSTANCE = new Singleton();
/* Static initialization is also doable if needed.
//static {
// private static final Singleton INSTANCE = new Singleton();
//}
*/
private Singleton() {}

public static Singleton getInstance() {
return INSTANCE;
}
}

As mentioned before if you can afford early loading, DO IT !!

1. Single threaded singleton

This is one of the simplest ways to implement a singleton and it is NOT thread safe (you cannot guarantee that there will be only one instance of the class in a multi-threaded environment). If you can guarantee that there will only be one thread poking around, then sure you can go ahead, but you’ve been warned !

1. public final class Singleton {
2. private singleton= null;
3. private Singleton (){}
4. public static Singleton getInstance() {
5. if(singleton == null) {
6. singleton = new Singleton();
7. }
8. return singleton;
9. }
10.}

The troubles begin at the line 4 where multiple threads can pass the if conditional and get to the line 5 which ultimately leads to multiple instances of the singleton class in the system which defeats the whole point of using singleton.

Notice how the constructor is made private to eliminate the ability to make an instance of the class outside the Singleton class. If you look carefully you will notice that the class is made final as well, this to indicate that the class cannot be inherited (private constructor also inhibit inheritance).

2. Draconian synchronization

To adapt the above code to a multi-threaded environment all we need to do is make sure that only one thread can execute the getInstance() method at a given time. Easiest way to do this is to use the synchronized keyword in Java for the method.

From performance standpoint this code is inefficient and has an unnecessary overhead. We will improve it more in the next version of it.

1. public final class Singleton {
2. private Singleton= null;
3. private Singleton (){}
4. public static synchronized Singleton getInstance() {
5. if(Singleton != null) {
6. Singleton = new Singleton();
7. }
8. }
9. }

3. Double-Checked Locking (DCL)

Earlier version of the singleton has a performance issue due to the use of the synchronized method but it can still be optimized further as follows. In this approach synchronization is applied to the critical section of the code and provides better performance than before.

public final class Singleton {
    // Pay attention to volatile
private volatile static Singleton uniqueInstance;

private Singleton() {}
public static Singleton getInstance(){
if (uniqueInstance==null) {
synchronized(Singleton.class){
if (uniqueInstance==null) {
uniqueInstance=new Singleton();
}
}
}
return uniqueInstance;
}
}

Why the variable is volatile ? volatile keyword on the declaration of the uniqueInstance member. This will tell the compiler to always read from, and write to, main memory, and not the CPU cache. So performance hit is still there even in this implementation as well.

4. Initialization-on-demand holder

public class Singleton{
private Singleton() {}
    private static class LazyHolder {
static final Singleton INSTANCE = new Singleton();
}
    public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}

This is a cute way to get a singleton using the inbuilt JVM constraints of class and object initialization. The JVM guarantees that the static class definition LazyHolder within is not initialized until the JVM determines that LazyHolder must be executed. The static class LazyHolder is only executed when the static method getInstance is invoked on the class Singleton, and the first time this happens the JVM will load and initialize the LazyHolder class. Since the class initialization phase is guaranteed by the JLS (Java Language Specification) to be serial, i.e., non-concurrent, no further synchronization is required in the static getInstance method during loading and initialization.

5. The ONE Line Killer.. The ENUM based singleton

We are now moving into advanced stuff here but the code remains rather simple. ENUMs are a special type of classes in Java and their behavior can be exploited to create THE most perfect singleton so far.

public enum Singleton {
SINGLETON;
public void anotherMethodOfTheSingleton(){
}
}

Some might think that it’s too simple, but this is the ironclad guaranteed implementation of a singleton that will not bow down to multiple instantiation. How does this work ? Well, the line 2 of the code will be boiled down to something like this,

public enum Singleton {
public final static Singleton SINGLETON = new Singleton();
    public void anotherMethodOfTheSingleton(){  
}
}

Another problem with conventional singletons are that once you implement serializable interface they are no longer remain singleton because readObject() method always return a new instance just like constructor in Java.

As you can see ENUM based singleton is more concise than all other ways to make a singleton, plus it provides the serialization machinery for free.

So, why singleton is bad ?

1. You Give Up on Testability

With singletons — the bad thing is that the getInstance() method is globally accessible. That means that you usually call it from within a class, instead of depending on an interface you can later mock. That's why it's impossible to replace it when you want to test the method or the class.

Singletons are nothing more than global state. Global state makes it so your objects can secretly get hold of things which are not declared in their APIs, and, as a result, Singletons make your APIs into pathological liars.
-Misko Hevery on his blog post on singletons.

2. Tight Coupling

Since the singleton presents a global state to other classes, it is often used everywhere in the code. This makes singletons in your application the center of gravity where all the rest of the code directly or indirectly depends upon. So a small change in the singleton can and will bring your system to it’s knees.

3. Singletons carry state till the app dies

Persistent state is the enemy of unit testing. One of the things that makes unit testing effective is that each test has to be independent of all the others. If this is not true, then the order in which the tests run affects the outcome of the tests. This can lead to cases where tests fail when they shouldn’t, and even worse, it can lead to tests that pass just because of the order in which they were run. This can hide bugs and is evil. Avoiding static variables is a good way to prevent state from being carried from test to test. Singletons, by their very nature, depend on an instance that is held in a static variable. This is an invitation for test-dependence.


That’s it for this time, hope you learnt something out of this post. If you did enjoy it and have some thoughts where this post can be improved, feel free to add a comment down below. And as always CLAPS are welcome :-D