Singleton design pattern: Everything

Imaji Pietersz
5 min readJun 2, 2021
Photo by Kelly Sikkema on Unsplash

Hy todos!! In my previous blog, we talk about is it really needed to study design patterns, their merits, and their demerits. As we came to a conclusion that it is beneficial to learn design patterns, today I am thinking of dive into an important and interesting design pattern: singleton design pattern.

Through this blog, you are going to cover almost every basic knowledge you should have before implementing this design pattern to your code. So cheers! Let’s get started.

Mainly there are three types of design patterns; Creational, behavioral, and structural. Singleton design pattern comes under creational design pattern.

Creational patterns are ones that create objects, rather than having to instantiate objects directly. This gives the program more flexibility in deciding which objects need to be created for a given case.

The singleton pattern is when a class is designed in such a way that it prevents the creation of objects outside of the class while also providing a mechanism to render its instance when the calling code requests it. For all requests, the same object is served. When we are using an external resource/ hardware interface such as a printer, could be costly. Then we have to keep it centralized. Not only that but also singleton is good for Logger, caching, and configuration. Singleton is used in other design patterns such as abstract factory, builder, prototype, and facade as well.

In simple terms, A singleton class should have only one instance, not more than one instance is created.

The main point here is we can’t let everyone create instances of the object.Therefore we are using a Private constructor here which restricts the instantiation of the class from other classes.

But we should let everyone access the same instance. To store that instance we use a Private static variable.

We restrict others to the creation of instances by making the constructor private. But when another class wants to access the object they can use the public static method: public static getter. The public static method that returns the instance of the class, is the global access point for the outer world to get the instance of the singleton class.

There are few ways to obtain this design pattern. Come with me! let’s go through it one by one.

  1. Eager initialization

The concept we use here is even though our consumers ask for an instance or not we initiate and store an instance. The problem is if we have to store lots of singleton objects in this way, even though creation is costly we have to initiate and store an instance even though we need it or not. This sounds like a waste of resources and money.

2. Lazy initialization

This is an optimization of eager initialization. Here we create an instance only when a consumer asks. This sounds great, right? So is this the best approach and no need to worry anymore? But wait! will this be the same for a multi-threaded environment as well? I wish but the answer is “NO”.

There are various trade-offs in the approaches described above. We won’t have any problems as long as we know there’s only one thread accessing the singleton object. The methods outlined above are sufficient. However, in a multi-threaded system, multiple threads may have access to the same line of code. This is where the issue arises.

  1. synchronized method approach:Thread Safe Singleton

To make a singleton class thread-safe, getInstance() method is made synchronized so that multiple threads can’t access it simultaneously.

The problem here is code is not efficient as every time when some class asks for an instance even after the creation it has to block the object at the class level. Unnecessarily we block the object as this is only needed at the moment of creation of the object. After that, there is no need for a synchronization method.

The solution is double-checking lock.

Lazy initialization with Double check locking

Here are two types of differences; we have used if close at two places and have used synchronized block instead of a synchronized method. We call the synchronized block only when the initiation of the instance. Afterward, it is not required to block every time some consumer wants to access an instance. In this mechanism, we overcome the overhead problem of synchronized code. In this method, getInstance is not synchronized but the block which creates instance is synchronized so that a minimum number of threads have to wait and that’s only for the first time.

Before we wrap up our article, quickly let's peak on when to use what in singleton pattern.

  1. Although eager initialization is simple to implement, it may waste resources and CPU time. Use it only if the cost of initializing a class is low in terms of resources or if your program requires a class instance at all times.

2. We can offer exception handling and instance control by using the Static block in Eager initialization.

3. We can create singleton classes in multi-threading environments using synchronized, but this can delay performance, thus we can utilize the Double-check locking mechanism instead.

So that's all for today. Hope you got a basic understanding of the singleton pattern, different approaches, their problems and when to use what approach through this blog.

Happy learning!

--

--