Thread-Safe Singleton Design Pattern in C#

Thread-Safe Singleton Design Pattern in C# with Examples

In this article, I will discuss How to Implement a Thread-Safe Singleton Design Pattern in C# with Examples. Please read our previous article discussing why we must 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 Safe in a Multithread Environment. As part of this article, we will discuss the following pointers in detail.

  1. What is Thread-Safe in Singleton Design Pattern?
  2. What is Lazy Initialization in the Singleton Design Pattern?
  3. How to Implement the Singleton Design Pattern in a Thread-Safe Manner in C#?
  4. Implementation of Thread-Safe Singleton Design Pattern using Locks.
  5. Double-Check Locking Approach to Implement Thread-Safe Singleton Design Pattern in C#.
  6. Thread-Safe Singleton Design Pattern in C# using Lazy<T>.
Example to Understand Thread-Safe in Singleton Design Pattern in C#.

A thread-safe Singleton design pattern in C# ensures that only one class instance is created, even in a multi-threaded environment. There are several ways to implement a thread-safe Singleton in C#.

Let’s understand How to Implement a Thread-Safe Singleton Design Pattern in C# with Examples. Let us first see the problem we face in a multithread environment if the Singleton Class is not Thread-Safe. So, create a class file with the name Singleton.cs and copy and paste the following code. The following code example is self-explained, so please go through the comment lines for a better understanding. 

using System;
namespace SingletonDemo
{
    public sealed class Singleton
    {
        //This variable value will be increment by 1 each time the object of the class is created
        private static int Counter = 0;

        //This variable is going to store the Singleton Instance
        private static Singleton Instance = null;

        //The following Static Method is going to return the Singleton Instance
        public static Singleton GetInstance()
        {
            //This is not thread-safe
            if (Instance == null)
            {
                Instance = new Singleton();
            }

            //Return the Singleton Instance
            return Instance;
        }
        
        private Singleton()
        {
            //Each Time the Constructor is called, increment the Counter value by 1
            Counter++;
            Console.WriteLine("Counter Value " + Counter.ToString());
        }

        //The following method can be accessed from outside of the class by using the Singleton Instance
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

The way we have created the above Singleton Class, it is not Thread-Safe in a Multithreaded environment. That means two threads at the same time may check the if (instance == null) condition, and it is also possible that both the threads found the condition as true, and hence, it will end up creating two instances of the Singleton Class.

Let’s modify the Main method of the Program class as follows to use multithread programming. As you can see in the below code, we are using Parallel.Invoke method and call PrintTeacherDetails and PrintStudentDetails methods parallelly. This will create two threads and invoke the two methods parallelly. Further, if you notice, we are calling the Static GetInstance() method of the Singleton class in each method. That means two different threads are now trying to call the same Static GetInstance() method of the Singleton class. Let us run the application, see the output, and check how many times the constructor of the Singleton class is executed.

using System;
using System.Threading.Tasks;
namespace SingletonDemo
{
    class Program
    {
        //Example to Understand Thraed-Safe Problem with Singleton Design Pattern
        //When use in a Multithreaded Environment
        static void Main(string[] args)
        {
            //The following Code will Invoke both methods Parallely using two different Threads
            Parallel.Invoke(
                //Let us Assume PrintTeacherDetails method is Invoked by Thread-1
                () => PrintTeacherDetails(),
                //Let us Assume PrintStudentDetails method is Invoked by Thread-2
                () => PrintStudentdetails()
                );
            Console.ReadLine();
        }

        private static void PrintTeacherDetails()
        {
            //Thread-1 Calling the GetInstance() Method of the Singleton class
            Singleton fromTeacher = Singleton.GetInstance();
            fromTeacher.PrintDetails("From Teacher");
        }

        private static void PrintStudentDetails()
        {
            //At the same time, Thread-2 also Calling the GetInstance() Method of the Singleton Class
            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, please read our Parallel Programming in C# with Real-Time examples article.

So, in our example, we are using the Parallel.Invoke method to access the GetInstance Method parallelly. That means, at the same time, multiple threads are accessing the GetInstance Method. The above code is not Thread-Safe because the way we have written it here, two different threads can evaluate the condition if (instance == null) simultaneously, and both threads find it true. They both will create instances that violate the singleton design pattern. So, now run the application, and it will give you the following output.

Example to Understand Thread-Safe Singleton Design Pattern in C#

The above output clearly shows that the counter value has incremented to 2, which proves that the constructor of the Singleton class is executed two times; as a result, two instances of the singleton class have been created in this case. So, if the Singleton class is not Thread-Safe, we may create multiple instances of the Singleton class in a Multithread Environment.

What is Lazy Initialization in Singleton Design Pattern in C#?

In our example, until and unless we invoke the GetInstance Method of the Singleton Class, the Singleton Instance will not be created. That means only the Singleton Instance will be created when we invoke the GetInstance Method of the Singleton class. This Delay of Singleton Instance creation is called Lazy Initialization in the Singleton Design Pattern.

The Lazy Initialization, i.e., the on-demand object creation of the Singleton Class, works fine when we invoke the GetInstance Method 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 create multiple instances of the singleton class when multiple threads invoke the GetInstance Method parallelly at the same time, which we just discussed. 

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

There are many ways to Implement the Thread-Safe Singleton Design Pattern in C#. They are as follows:

  1. Thread-Safety Singleton Implementation using Lock.
  2. Implementing Thread-Safety Singleton Design Pattern using Double-Check Locking.
  3. Using Eager Loading to Implement Thread-Safety Singleton Design Pattern
  4. Using Lazy<T> Generic Class to Implement Lazy Loading in Singleton Design Pattern.

We will discuss all the above mechanisms to Implement the Thread-Safe Singleton Design Pattern in C#. In this article, we will discuss how to use Locks and Double-Check Locking Mechanisms to implement the Thread-Safe Singleton Design Pattern in C#, which will create only one instance of the Singleton Class in a Multithread environment. The rest Two Mechanisms are going to be discussed in our next article.

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

Let us discuss using locks to implement the Thread-Safe Singleton Design Pattern in C#. You must remember that Locks are the best option to handle the singleton instance in a multithread environment. Using locks, we can synchronize the method. So that only one thread can access it at any given point in time. 

For a better understanding, please modify the Singleton Class as follows. In the following code, we lock the shared resource using the lock object and check whether the instance is created. If the instance is already created, we return that instance; else, we will create the instance and then return that instance. The most important point is that as long as one thread locks the resource, no other thread can access the resource. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace SingletonDemo
{
    public sealed class Singleton
    {
        //This variable value will be increment by 1 each time the object of the class is created
        private static int Counter = 0;

        //This variable is going to store the Singleton Instance
        private static Singleton Instance = null;

        //To use the lock, we need to create one variable
        private static readonly object Instancelock = new object();

        //The following Static Method is going to return the Singleton Instance
        public static Singleton GetInstance()
        {
            //This is thread-safe
            //As long as one thread locks the resource, no other thread can access the resource
            //As long as one thread enters into the Critical Section, 
            //no other threads are allowed to enter the critical section
            lock (Instancelock)
            { //Critical Section Start
                if (Instance == null)
                {
                    Instance = new Singleton();
                }
            } //Critical Section End
            //Once the thread releases the lock, the other thread allows entering into the critical section
            //But only one thread is allowed to enter the critical section

            //Return the Singleton Instance
            return Instance;
        }
        
        private Singleton()
        {
            //Each Time the Constructor is called, increment the Counter value by 1
            Counter++;
            Console.WriteLine("Counter Value " + Counter.ToString());
        }

        //The following method can be accessed from outside of the class by using the Singleton Instance
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

With the above changes in place, now run the application, and you will get the following output.

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

The above code implementation using lock solves the Singleton Design Pattern Thread-Safe issues in a multithreading environment. But the problem is that it slows down your application as only one thread can access the GetInstance method anytime. We can overcome the above problem by using the Double-Checked Locking mechanism.

Double Checked Locking Approach to Implement Thread-Safe Singleton Design Pattern in C#.

In the Double-Checked Locking mechanism to implement Thread-Safe Singleton Design Pattern in C#, first, we will check whether the instance is created. If not, then only we will synchronize the method using the lock. For a better understanding, please modify the Singleton class as follows. Here, you can see we check the instance two times to see whether it is null. If it is not null, then we are returning the Singleton instance. If it is null, we use the lock to ensure only one thread can enter the critical section. Within the lock block, we check the null condition to ensure only one instance of the Singleton Class will be created. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace SingletonDemo
{
    public sealed class Singleton
    {
        //This variable value will be increment by 1 each time the object of the class is created
        private static int Counter = 0;

        //This variable is going to store the Singleton Instance
        private static Singleton Instance = null;

        //To use the lock, we need to create one variable
        private static readonly object Instancelock = new object();

        //The following Static Method is going to return the Singleton Instance
        public static Singleton GetInstance()
        {
            //This is thread-Safe
            if (Instance == null)
            {
                //As long as one thread locks the resource, no other thread can access the resource
                //As long as one thread enters into the Critical Section, 
                //no other threads are allowed to enter the critical section
                lock (Instancelock)
                { //Critical Section Start
                    if (Instance == null)
                    {
                        Instance = new Singleton();
                    }
                } //Critical Section End
                //Once the thread releases the lock, the other thread allows entering into the critical section
                //But only one thread is allowed to enter the critical section
            }
            
            //Return the Singleton Instance
            return Instance;
        }
        
        private Singleton()
        {
            //Each Time the Constructor is called, increment the Counter value by 1
            Counter++;
            Console.WriteLine("Counter Value " + Counter.ToString());
        }

        //The following method can be accessed from outside of the class by using the Singleton Instance
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

With the above changes in place, now run the application, and you will see the output as expected, as shown in the below image.

Double Checked Locking Approach to Implement Thread-Safe Singleton Design Pattern in C#

Thread-Safe Singleton using Lazy<T>:

There are several ways to implement a thread-safe Singleton in C#. One common and recommended approach is to use the Lazy<T> type for lazy initialization, which is inherently thread-safe. Here’s an example of how to create a thread-safe Singleton using Lazy<T>:

using System;
namespace SingletonDemo
{
    public sealed class Singleton
    {
        //This variable value will be increment by 1 each time the object of the class is created
        private static int Counter = 0;

        // The private static instance ensures lazy initialization.
        private static readonly Lazy<Singleton> instance = new Lazy<Singleton>(() => new Singleton());

        // Private constructor to prevent direct instantiation.
        private Singleton()
        {
            // Initialization code here
            //Each Time the Constructor is called, increment the Counter value by 1
            Counter++;
            Console.WriteLine("Counter Value " + Counter.ToString());
        }

        //The following Static Method is going to return the Singleton Instance
        public static Singleton GetInstance()
        {
            return instance.Value;
        }

        //The following method can be accessed from outside of the class by using the Singleton Instance
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}
In this Example:
  • We use a private static Lazy<Singleton> field to hold the instance of the class. The Lazy<T> type ensures that the instance is created only when it is first accessed, providing efficient lazy initialization.
  • The constructor of the Singleton class is private, preventing direct instantiation from outside the class.
  • The public GetInstance method returns the Value of the Lazy<Singleton> field, which will create the instance if it doesn’t exist or return the existing instance if it does.

This implementation is thread-safe because the Lazy<T> type guarantees that the initialization of the instance is atomic and safe in a multi-threaded environment. It also ensures that only one instance is created, even when accessed concurrently from multiple threads. With the above changes in place, now run the application, and you will see the output as expected, as shown in the below image.

Thread-Safe Singleton using Lazy<T>

When to use Thread-Safe Singleton Design Pattern in C#?

You should consider using the thread-safe Singleton design pattern in C# when you need to ensure that a class has only one instance throughout the lifetime of an application, and you anticipate that the class may be accessed concurrently by multiple threads. The thread-safe Singleton pattern is essential in scenarios where:

  • Shared Resource Management: You have a resource that should be shared among multiple parts of your application, such as a database connection pool, a configuration manager, or a logging service.
  • Concurrency Control: You need to ensure that the initialization of the Singleton instance is safe and atomic when multiple threads may attempt to access it simultaneously.
  • Resource Efficiency: You want to optimize resource usage by creating the Singleton instance only when it is first accessed rather than at application startup.
  • Lazy Initialization: You want to defer the creation of the Singleton instance until it is actually needed, which can be beneficial for performance and resource utilization.

Here are some specific scenarios where a thread-safe Singleton pattern can be valuable:

  • Database Connection Pooling: Managing a pool of database connections that must be shared across multiple parts of an application.
  • Logging: Ensuring that log messages are consistently written to a single log file or destination, even when multiple threads are logging concurrently.
  • Configuration Management: Storing and accessing application configuration settings in a centralized way.
  • Caching: Implementing a cache manager that stores frequently used data in memory.
  • Resource Management: Controlling access to a limited resource, such as a hardware device or network connection.

In these scenarios, using a thread-safe Singleton pattern helps prevent race conditions, data corruption, and resource contention issues that can arise when multiple threads attempt to create or access a shared instance concurrently.

In the next article, I will discuss the Lazy vs Eager Loading in Singleton Design Pattern in C# with Examples. In this article, I explain How to Implement a Thread-Safe Singleton Design Pattern in C# using the Lock and Double-Check Locking Mechanism in C# with Examples. I hope you enjoy this How to Implement Thread-Safe Singleton Design Pattern in C# with Examples article. Please give your feedback, questions, and suggestions about this article.

21 thoughts on “Thread-Safe Singleton Design Pattern in C#”

  1. This is way overkill!
    You don’t need to lock or the counter.

    This is the simplest thread-safe method: simply assign the value directly to the static variable.
    Thus:

    public sealed class Singleton
    {
    private static Singleton instance = new Singleton();
    private Singleton()
    {
    // initialisation code…
    }
    public static Singleton Instance
    {
    get
    {
    return instance;
    }
    }
    }

    “Since the CLR automatically calls a type’s class constructor the first time code attempts to access a member of the class, the first time a thread queries Singleton’s Instance (get) method, the CLR will automatically call the class constructor, which creates an instance of the object. Furthermore, the CLR ensures that calls to a class constructor are thread safe.”

    The only downside of this would be if your class has other static members that are accessed first, the instance would be created at that time, which might not be desirable. In this case, you could use your method, except you still don’t need to “count” or “lock”, you can simply use Interlocked.CompareExchange.
    Thus:

    static Singleton singleInstance;
    ///
    /// Get the one and only instance of this class.
    ///
    public static Singleton Instance
    {
    get
    {
    if (null == singleInstance)
    {
    Interlocked.CompareExchange(ref singleInstance, new Singleton(), null);
    }
    return singleInstance;
    }
    }

  2. Mohammad Mostafizur Rahman

    Is it necessary to put null checking just before the line “lock (Instancelock)” ?

  3. Here I need to 2 threads parallelly and that should have one instance
    I guess lock will block the thread if one is in progress

Leave a Reply

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