Search
Close this search box.

Singleton Design Pattern – The Pragmatic Approach part 3

Singleton Design Pattern – The Pragmatic Approach part 3

Alright! In our previous articles, we understood some nuances, concerns, and considerations of why we need Singleton and we also tried one way to achieve it through static keyword which had few loopholes. Let’s try some things ourselves to overcome those loopholes so that we have full control on the Singleton instance of our class.

I want to stress it again

 that you please read the first part of this article to get a complete and thorough context of the talk. The source code for this blog is available under my account on GitHub here. Please feel free to leave your pull requests in case you think I can improve it in any way.

A Basic Attempt to Ensure Singleton Instance of a Class

Let’s try to evolve further. Stop and think a bit. Write on a piece of paper a list of everything you might require, giving a guarantee that only one instance of a class gets created in code and the moment anybody tries to create the second instance, it disallows it and throws some illegal operation exception— or maybe returns the same instance that you had created in the first go.
Here is what I tried in a step by step manner. Try to match it with the notes you just scribbled and see if you were thinking along the same lines:

  1. One thing is sure that if my constructor is public, I can’t stop my colleagues from using the new keyword to instantiate the class. So, the very first thing that I did was to apply private access specifier to the constructor method. Cool!
    pragmatic

2. But now the next problem arises. The moment I applied the private access specifier, the language compiler will bar even me (an unbiased compiler) from creating the instance. Huh! But we’ve to create an instance. At least one instance. Isn’t it? I figured out a way. There is still a place left on this planet which can invoke that private constructor through new operator to get an instance. That place is inside the class itself. Since the instance is not possible, hence calling instance methods will not be possible, I introduced a static method GetInstance on the class so that I can call something from the outside. GetInstance does the trick of creating class instance even though constructor is private. Here we go:

pragmatic

Hey, wait! Something is still wrong here. We wanted to have one instance but we also wanted a maximum of one instance as well. Now we’ve overcome that private constructor problem but will the call to GetInstance method not create a new instance every time? It will.
So, to make it a truly singleton implementation, I introduced a private static reference to keep a check if an instance already exists. Have a look at a basic complete implementation:

pragmatic

Nice. Finally, we reached a stage where we have a truly singleton class. Either there will be zero or at maximum 1 instance. Now, the calling semantics from the consumers will also change as shown below as we can’t use new keyword anymore to get an instance of the Logger class. Now we need to call the GetInstance method instead at the call site as shown below:

pragmatic

Everything looks cool and sorted. Isn’t it? We wanted to ensure singleton instance for our class and we achieved it. Really? No, gentlemen. It is a wild world out there and real-world enterprise applications aren’t that simple as I’ve mentioned so far.

Real world applications employ a concept called multi-threading where you can kick-start more than one thread to get your tasks done faster as threads run in parallel using various CPU cycle switching algorithms e.g. round-robin. So, all that lovely code to create singleton instance can come crashing if your application has more than one thread. Let’s see how. We’ve more problems to overcome.

We Aren’t Truly Singleton Yet: Preparing Yourself for the Nuances of Multithreaded World

So first let’s understand where things can go wrong in the multi-threaded world in the implementation we’ve done so far. Consider the below portion of code which the soul of our singleton implementation. Line numbers are just for reference.

pragmatic

Let’s say you’ve got two threads in all in your systems and both intend to get the singleton instance of the Logger class. Let’s call them T1 and T2.
Code executed by T1 and T2:

pragmatic

Let’s say your operating system is following a round-robin algorithm for context switching inside CPU and both threads have got equal priority.
Now we have just started the application. Let’s say the code running on T1 wanted to log something so it required the singleton instance and it is executing GetInstance method. So, it executed line # 1. It learned that singleton reference is currently null. Cool. Let’s move further.
But, the moment it was about to execute line # 2 and 3 context switching happened and control went to thread T2. We’re assuming a single core CPU here. T2 also wants to log something so it goes ahead and tries to execute GetInstance method. Incidentally, it turned out to be fast and it was able to execute the entire method in single CPU cycle so it was able to instantiate “Singleton” and then context switching happened.
Now T1 loaded its older context and realized that I have to start at line # 2. It remembered that Singleton wasn’t initialized, so it goes ahead and executes line # 2,3 & 4. Whoooaaa. We just instantiated our Singleton twice and our implementation stands broken ☹.
So, we require a fix here. The main problem here is the multi-threading world. Code line # 1, 2, 3 and 4 are critical pieces of code from threading stand-point. I need a mechanism so that if one thread is executing them, then the other thread should just wait before line # 1 else he might get stale/wrong information about instances. So I need to safeguard my code line # 1,2,3 & 4 against several threads running them simultaneously.
This thread synchronization is possible in C# using lock keyword. Let’s change the implementation to fix the problem (refer to SingletonWithLockingTextLogger.cs):

pragmatic

We’ve used an object instance on which lock is applied. .NET guarantees that only thread at a time can obtain lock on the synchronization block of an object. Now the moment T1 executed line # 1, no matter how many CPU cycles come and go, T2 will have to wait before line # 1 until and unless T1 has reached line # 6. The moment T1goes outside the locked code block, then T2 will enter and it will see the correct and up-to-date information that singleton is already initialized.
Finally, we’ve reached an implementation of creating singleton instances which is of real use and can be put to production deployment of an enterprise software.
Now we’ve got the functional correctness of Singleton instances. But you must have heard your manager or interviewer saying this common phrase – “Make this program run faster”. Of course, speed is everything in the world of computers. If two programs are achieving the same objective but the winner is the one which can do it in less time comparatively.

Can Our Application Perform Better?

Unknowingly, we’ve done something which has a performance cost. Let’s revisit the crucial piece of code. The point here is that anyone who wants a Logger class instance will invoke GetInstance method and he must acquire the lock. We’ve been following web application where we were trying to implement the singleton for all the logging needs of a single web call. Imagine an application like the winForm desktop application or a Windows service application which keeps running 24*7. This method might get called a million times every day from various components of your distributed application as your application process remains alive for weeks and months. Correct?
So essentially your application code acquires lock a million times to get a singleton instance. Isn’t it? Your application acquires lock a million times which is a costly affair in terms of performance and memory. Always know this fact that locks are a costly data structure.
Now take a pause and think. Do you really require to take that lock a million times?
The answer is no. It is all about the conflict which can happen when instantiation hasn’t happened for the first time only. Once an instance has got created, nobody gives a damn about the lock as every subsequent execution will have to simply return the singleton instance which is already created.

pragmatic

How can we overcome this performance issue which can be bad for my program as it grows? Let’s move on to next section to see the resolution.

Note:

If you are running a single user and single threaded console application containing few scores of log statements on a 32 GB RAM server, then this performance improvement might not seem that worthy. For every other application in this world, you must know this.

Making Your Programs Run Faster in Multithreaded World: Double Checked Locking

So, we understand the fact that locking is relevant only until the time our singleton instance isn’t instantiated. Once the singleton is instantiated, we can simply check for it being non-null and return the non-null instance. So, what you can do is to add an additional null checking statement surrounding the locked code block as null checking is an extremely lightweight operation when compared to taking a lock for thread-synchronization:

pragmatic
pragmatic

This is Not the Only Way to Write Singletons

There are some other variations of writing this piece of code which we were finally able to evolve over last few sections. See, at the end of the day, what we want is that our below two objectives should be met irrespective of what code we write:

  1. One and only one instance of the class should get created.
  2. The above statement should be always true. It should be true whether my application is single threaded or multi-threaded.

To ensure that the first objective wasn’t that difficult, but the second objective requires us to understand some complex concepts of multi-threading world. To ensure thread safety or thread synchronization in a multi-threaded application, every language provides many built-in features which you can leverage to get the same effect for which we wrote code. It is like reinventing the wheel if we aren’t using those built-in language features.
So, in place of doing locking, double checking and things like that, you can use these smart language features, so your lines of code get reduced but the intent remains the same. You also end up having same code written differently which we can call a variation. Here are few possible variations:

  1. Simply use in-line static initializer (Eager instantiation):

    So here, we use CLR’s capability which gives us the guarantee that any static initialization will happen only once in a thread-safe manner. Please note that class has been decorated with a sealed keyword to avoid inheritance. This can be a downside in this implementation as we originally thought that our Singleton class should be able to participate in inheritance in case we’re changing an already existing application.  pragmatic

  2. Lazy Instantiation by introducing static constructor:

    In this variation, we introduce an explicit static constructor in Logger Having an explicit static constructor instructs the compiler to not decorate the class with before field in it keyword (while creating MSIL code) which causes eager instantiation of static classes.

    pragmatic

    So, we figured out a way for lazy instantiation in statics also. 😊

.NET 4 Lazy class-based implementation:

A very sweet and short implementation in .NET v4.0 using built-in Lazy class in framework class library (FCL):

pragmatic

It requires you to have at least .NET Framework 4 and C# 6.0 (VS 2015) or higher for the above code to work.

Singletons are Considered a Bad Design Choice

I know you will be upset with me that after such a mammoth article, I’m telling you this that Singletons are a bad design choice. This is not always the case, but it is good to know few downsides which are as below:

  1. They introduce a global context variable which is considered a bad design choice.
  2. Implementation is not transparent to the consumer. Instead of using “new” keyword to instantiate a singleton class, now you use a special method (GetInstancein my implementation) to get the Singleton So when you refactor your existing code and convert one of your classes to Singleton, then you will have to change code at all the call sites. By the way, this is not a heavy price to pay to make your program behave functionally correct and become better performing.

Concluding Thoughts: You Need a Definition to Tell in Your Next Interview

To cheer you up, I look at Singletons as “Controlled Globals”. The idea is that don’t try to use Singletons just because you want to make something global. When you have a dire need for creating and managing singletons, then only you should think of singletons. When Singletons help ensure the functional correctness of your program and make it better performing, then you should be confident of using it. Some very famous use cases which are a great fit for Singletons are loggers, print spoolers, database connections, etc.

Never think of patterns first. Always evolve!

Never try to mug up the definition of any design pattern. Look at use cases around yourself. Look at products you are working upon. Look at frameworks or libraries that you use in your day to day life. “Application” class in ASP.NET is Singleton. Why?
If you a tell a child to learn the word “round”, he will struggle. The moment you show him a ball and tell him that it is round, then he learns.
I could have provided the formal definition of this pattern at the beginning itself, but I left it for the end. Patterns are not something you should begin with while solving a problem. Solve a problem first. Solve one more problem. Maybe solve one more. And then you realize that several problems are getting solved repeatedly in the same way. Then it becomes a pattern. A design pattern. 

Design pattern terminology is a jargon used in programmer’s community. It brings succinctness in your discussions.

I’m giving the definition here just for the sake of completeness of the article from Gang of Four (GOF) directory:

pragmatic

Final thoughts

Tell me and I will forget.
Teach me and I will remember.
Involve me and I will learn.

Involvement comes with coding and discussion. Try to see if Singleton Design pattern is a good fit in any of the use cases when you start your next greenfield project or do some refactoring or try to solve a performance issue. Don’t forget to talk about whatever you have learned here with your colleagues, friends, and acquaintances. You can learn it only when you get involved. There isn’t a workaround for it.
Design patterns aren’t about definitions, they are about patterns which evolve out of use cases.

Points of Interest

  • Did you notice the volatile keyword in “We aren’t truly singleton yet: Preparing yourself for the nuances of multithreaded world” section? What is the significance of using it in a multi-threaded environment? What advantages does give?
  • You saw other possible implementations of Singleton Design Pattern in “This is not the only way to write singletons” section. Can you explore their advantages and disadvantages?
  • Explore the case of Singleton Design Pattern where it has been used in .NET Framework here. A cheat-sheet of various design patterns used in .NET Framework class library is here.
  • Evaluate other places where you can find it useful to apply singleton design pattern. I’m quoting some examples below. Ponder on the reasons as to why it makes sense to use the design pattern in below cases and what problems I might face if I don’t use it?
  • Maintaining configurations from your application configuration file.
  • Communication of the chat windows in a chatting application using a socket – Would you want to open a new socket for every new chat window? Is creating socket a heavy operation?
    Check out part 1 here. 
    Check out part 2 here.

Report

The FORRESTER WAVE™: End-User Experience Management, Q3 2022

The FORRESTER WAVE™: End-User Experience Management, Q3 2022