Thread-safe Singleton Design Pattern in C#

Thread-safe Singleton Design Pattern in C# with Examples

In this article, I am going to discuss how to implement the Thread-safe Singleton Design Pattern in C# with examples. Please read our previous article before proceeding to this article where we discussed Why do we need to create the Singleton Class as Sealed in C# with examples. As of now, the way we have implemented the singleton design pattern is not Thread safety in a multithread environment.

Let’s understand the Thread-safe Singleton Design Pattern in C# with one example.

First, create the Singleton class as shown below.

namespace SingletonDemo
{
    public sealed class Singleton
    {
        private static int counter = 0;     
        private static Singleton instance = null;  
        public static Singleton GetInstance
        {
            get
            {
                if (instance == null)
                    instance = new Singleton();
                return instance;
            }
        }  
        private Singleton()
        {
            counter++;
            Console.WriteLine("Counter Value " + counter.ToString());
        }    
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

Let’s modify the Main method of Program class to use multithread programming as shown below.

namespace SingletonDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Parallel.Invoke(
                () => PrintTeacherDetails(),
                () => PrintStudentdetails()
                );
            Console.ReadLine();
        }

        private static void PrintTeacherDetails()
        {
            Singleton fromTeacher = Singleton.GetInstance;
            fromTeacher.PrintDetails("From Teacher");
        }

        private static void PrintStudentdetails()
        {
            Singleton fromStudent = Singleton.GetInstance;
            fromStudent.PrintDetails("From Student");
        }
    }
}

Here, within the main method, we use Parallel.Invoke method to invoke multiple methods parallelly, This concept is introduced in .NET Framework 4.0. If you are new to parallel programming then please read the following article where we discussed the Parallel Programming in C# with real-time examples.

Parallel Programming in C#

How to use Parallel.Invoke in C#

So in our example, we are using the Parallel.Invoke method to access the GetInstance property parallelly, means at the same time multiple threads are accessing the GetInstance property. The above code is not Thread safe because the way we code here two different threads can evaluate the condition if (instance == null) at the same time and both the threads found it to be true and they both will create the instances, which violates the singleton design pattern.

So, now run the application and it will give you the following output.

Thread-safe Singleton Design Pattern in C#

The above output clearly shows that the counter value has incremented to 2 which prove that multiple instances of the singleton class have been created in a multithreaded environment.

What is Lazy Initialization in the Singleton Design Pattern:

In our example, until and unless we invoke the GetInstance Property of the Singleton class, the Singleton instance is not created. That means when we invoke the GetInstance Property of the Singleton class then only the Singleton object is created. This Delay of Singleton Instance creation is called Lazy Initialization.

How to use Multithreads in Singleton:

The lazy initialization i.e. the on-demand object creation of the singleton class works fine when we invoke the GetInstance property in a Single threaded environment. But in a multi-threaded environment, it will not work as expected. In a multi-thread environment, the lazy initialization may end up creating multiple instances of the singleton class when multiple threads invoke the GetInstance property parallely at the same time which we already discussed in our previous example. 

How to implement a Thread-safe Singleton Design Pattern in C#?

We can use Locks in C# to control the thread race condition in a multithreaded environment. Along with Locks we have other options too available that we will discuss in our upcoming articles. In this article, we will discuss how to use Locks to handle singleton instance in a multi-threaded environment.

Implementation of Thread-safe Singleton Design Pattern in C# using locks.

Let us discuss how to implement the Thread-safe Singleton Design Pattern in C# using locks to handle the multithreaded environment. The point that you need to remember is Locks are the best option to handle the singleton instance,

Using locks we can synchronize the method. So that only one thread can access it at any given point of time. In the following code, we lock the shared resource and then checks whether the instance is created or not. If the instance is already created then we simply return that instance else we will create the instance and then return that instance.

namespace SingletonDemo
{
    public sealed class Singleton
    {
        private static int counter = 0;
        private static readonly object Instancelock = new object();
        private Singleton()
        {
            counter++;
            Console.WriteLine("Counter Value " + counter.ToString());
        }
        private static Singleton instance = null;
       
        public static Singleton GetInstance
        {
            get
            {
                lock (Instancelock)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                    return instance;
                }
            }
        }
        
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

Now run the application and you will get the following output.

thread safe singleton design pattern

The above code implementation using lock solves the multithreading issue. But the problem is that it is slow down your application as only one thread can access the GetInstance property at any given point of time. We can overcome the above problem by using the Double checked locking mechanism.

Double checked locking approach for Thread-safe Singleton Design Pattern in C#.

In Double checked locking mechanism, first, we will check whether the instance is created or not. If not then only we will synchronize the method as shown below.

namespace SingletonDemo
{
    public sealed class Singleton
    {
        private static int counter = 0;
        private static readonly object Instancelock = new object();
        private Singleton()
        {
            counter++;
            Console.WriteLine("Counter Value " + counter.ToString());
        }
        private static Singleton instance = null;
       
        public static Singleton GetInstance
        {
            get
            {
                if (instance == null)
                {
                    lock (Instancelock)
                    {
                        if (instance == null)
                        {
                            instance = new Singleton();
                        }

                    }
                }
                return instance;
            }
        }

        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

Now run the application and you will see the output as expected. In the next article, I am going to discuss the Lazy vs Eager loading in the Singleton design pattern with some examples.

SUMMARY

In this article, I try to explain the Thread-Safe Singleton Design Pattern in C# step by step with a simple example. I hope this article will help you with your need. I would like to have your feedback. Please post your feedback, question, or comments about this article.

5 thoughts on “Thread-safe Singleton Design Pattern in C#”

Leave a Reply

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