Sitemap
Snigdha Sanat

Snigdha Sanat

Senior Software Engineer. LinkedIn: https://www.linkedin.com/in/snigdha-sanat-760b9785/. Youtube: https://www.youtube.com/@SnigdhaSanat

Singleton pattern

6 min readDec 13, 2022

--

The Singleton design is used for situations where it is necessary to have a unique instance. Think of connection pools, thread pools, cache, and settings(system preferences) in your machine. What would happen if you have more than one instance of system preferences? Inconsistent behaviour will lead to a lot of confusion.

We will look at the standard way of creating a singleton class, and then understand how it ensures that a second instance can’t be created. Singleton Design pattern builds upon static variables, static methods and access modifiers. We will see how they all come together.

Arriving at the design

Let’s start with the a SimpleSingletonClass that has some access modifier:

<AccessModifier> SimpleSingletonClass{
//constructor
public SimpleSingletonClass(){}
}

Depending upon the AccessModifier being public, protected or private, SimpleSingletonClass can be instantiated from anywhere; or from within the package or its subclasses; or only from within the same class.

So what happens if the class SimpleSingletonClass is made private? It can only be accessed from within the same SimpleSingletonClass, neither from its subclasses, nor from the same package. The catch? From within the same SimpleSingletonClass, it can be accessed more than once though, using new SimpleSingletonClass(), and creating multiple instances. So making the class private does not serve our purpose.

What if the class is kept public, but its constructor is made private?

public SimpleSingletonClass{

//PRIVATE constructor
private SimpleSingletonClass(){}

}

Now, since the constructor is private, new SimpleSingletonClass() can be called only from within the same class SimpleSingletonClass.

From outside the class, we can grab an already created instance(say simpleSingletonClassObject) of SimpleSingletonClass, to call new SimpleSingletonClass(), as shown below:

simpleSingletonClassObject.new SimpleSingletonClass();

But we cannot instantiate this simpleSingletonClassObject in the first place, because the constructor of simpleSingletonObject is private. It is like a chicken-egg problem- to create a new object using new SimpleSingletonClass() we need simpleSingletonClassObject, but to create simpleSingletonClassObject, we need to be able to use new SimpleSingletonClass() outside the SimpleSingletonClass.

What next then? We know that the private constructor of SimpleSingletonClass can be accessed from within the class. We make use of this fact, and define a method getSingletonInstance() inside the class to access it. This method takes the responsibility of getting us the instance.

public class SimpleSingletonClass {

//PRIVATE constructor
private SimpleSingletonClass(){};

public static SimpleSingletonClass getSingletonInstance(){
return new SimpleSingletonClass();
}
}//SimpleSingletonClass
public class Client {
public static void main(String[] args) {
SimpleSingletonClass object=SimpleSingletonClass.getSingletonInstance();
}//main
}

Ensuring accessibility of the private constructor from the method

The method getSingletonInstance returns an instance of the SimpleSingletonClass. Since it is within the class SimpleSingletonClass, it has access to its private constructor, and so it can call new SimpleSingletonClass().

Ensuring accessibility of the method from outside the class

Since this method itself is public, anyone can call it in order to instantiate an object of SimpleSingletonClass. Being a static method, you don’t need an object of SimpleSingletonClass (like simpleSingletonClassObject) either to call this getSingletonInstance() method (which was the root cause of the chicken-egg problem earlier). It can be called on the class itself. So the method can be called from anywhere.

That completes the accessibility chain of accessing the method from outside, and the method itself accessing the private constructor.

Ensuring that only one object can be created

Accessibility being solved now, understand that even if the method can be called from anywhere, and of course multiple times, there cannot be more than one instance of SimpleSingletonClass created. How do we achieve this? We make a few modifications to the method definition as below:

public class SimpleSingletonClass {

//PRIVATE ctor
private SimpleSingletonClass(){};

private static SimpleSingletonClass theOnlyObject;

public static SimpleSingletonClass getSingletonInstance(){
if(theOnlyObject==null){
theOnlyObject=new SimpleSingletonClass();
}
return theOnlyObject;
}
}//SimpleSingletonClass

We create a static variable theOnlyObject to hold the singleton instance.
Then inside the method, the null check ensures that the object is instantiated only once. Subsequent calls to the method from other places will return the now already created theOnlyObject. The variable theOnlyObject being static, belongs to the class SimpleSingletonClass.

Get Snigdha Sanat’s stories in your inbox

Join Medium for free to get updates from this writer.

So the Singleton Design pattern builds upon the static variable theOnlyObject, static method getSingletonInstance(), a private constructor and a public method getSingletonInstance() to access the constructor.

Note that this is lazy instantiation, so that it is resource economic. We don’t bother calling the getSingletonInstance() method and creating the object, unless we actually need to.

Definition

The Singleton pattern ensures a class has only one instance, and provides a global point of access to it (through the getSingletonInstance method here)

Multiple threads

Until now, we have been carrying on the discussion assuming that only one thread exists. But the real world rarely is single threaded. What happens to theOnlyObject variable holding the reference to the one and only instance of the Singleton class, when multiple threads access it?

It might, and most of the times it will, behave in an unexpected way then. We are relying upon the null check:

if(theOnlyObject==null){
theOnlyObject=new SimpleSingletonClass();
}

But what if the below (unfortunate) sequence of events unfolds in time snaps T1, T2, T3 and T4?

T1: thread 1 checks the null check condition in the getSingletonInstance method
, evaluates to true
T2: thread 2 checks the null check condition in the getSingletonInstance method
,evaluates to true, since thread 1 hasn't created the theOnlyObject yet,
so it is still null
T3: thread 1 now creates the 'theOnlyObject'
T4: thread 2 creates ANOTHER 'theOnlyObject', as when it checked the null
condition in time T2, thread 1 hadn't created 'theOnlyObject' till then,
and so thread 2 passed the null check. But now in time T4, we already
have an 'theOnlyObject' created by thread 1 in T3.

The simplest way out of this is to use the synchronized keyword, which ensures that each thread waits for its turn.

public static synchronized SimpleSingletonClass getSingletonInstance(){
if(theOnlyObject==null){
theOnlyObject=new SimpleSingletonClass();
}
return theOnlyObject;
}

But synchronisation is expensive. Also, after theOnlyObject is set by the first call(thread) to the getSingletonInstance() method, the subsequent threads now accessing the synchronized method turn by turn will anyway be failed by the null check, ensuring that no subsequent creation of the object happens. This makes the synchronized keyword redundant.

The problem surfaces only when multiple threads access the null check at the same time, evaluates to true (because no object creation happens till then by another thread), and then each thread goes on to create its own object. So while we do need synchronisation, its placement in the code needs modification. So we place the synchronized keyword where the (unfortunate) sequence of events actually starts- which is AFTER the null check. See the code below.

public static SimpleSingletonClass getSingletonInstance(){
if(theOnlyObject==null){

//---synchronised block starts
synchronized (SimpleSingletonClass.class){
if(theOnlyObject==null){
theOnlyObject=new SimpleSingletonClass();
}//inner null check
}//synchronised block
//---synchronised block ends

}//outer null check
return theOnlyObject;
}

If we simulate the earlier sequence of events in T1, T2, T3 AND T4, even if multiple threads pass the outer null check, only one of them can enter the now synchronised block at a time. The first thread to enter creates theOnlyObject. Then when it is turn for the second thread to enter the synchronized block(having already passed the outer null check), the theOnlyObject now having been created by the first thread, the inner null check fails for the second(and all subsequent) thread(s).

This lets the outer null check do its job. The synchronised keyword takes over only when the outer null check fails, like in the race condition depicted in T1, T2, T3 and T4; instead of taking up the job all the time. This makes it resource economic.

Catches with the singleton pattern

In the scenario of multiple classloaders, since each of them can load a class once, it means each of the classloaders can load its own version of a Singleton class.

Comparison with global variable

A Singleton pattern ensures that only one instance of a class is in the app, and provides a global point of access to it. A global variable, while can provide the global point of access, cannot ensure that only one instance of a class is created. Also a global variable can’t provide lazy instantiation, while a singleton pattern can.

Code examples

Code examples are here.

--

--