Back to: Design Patterns in C# With Real-Time Examples
Thread-Safe Singleton Design Pattern in C# with Examples
In this article, I am going to discuss How to Implement Thread-Safe Singleton Design Pattern in C# with Examples. Please read our previous 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 Safe in a Multithread Environment. As part of this article, we are going to discuss the following pointers in detail.
- What is Thread-Safe in Singleton Design Pattern?
- What is Lazy Initialization in the Singleton Design Pattern?
- How to Implement the Singleton Design Pattern in a Thread-Safe Manner in C#?
- Implementation of Thread-Safe Singleton Design Pattern using Locks.
- Double-Check Locking Approach to Implement Thread-Safe Singleton Design Pattern in C#.
Example to Understand Thread-Safe in Singleton Design Pattern in C#.
Let’s understand How to Implement Thread-Safe Singleton Design Pattern in C# with Examples. Let us first see the problem that 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 then copy and paste the following code into it. 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, it is possible that two threads at the same time, 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, in each method, we are calling the Static GetInstance() method of the Singleton class. That means now, two different threads, trying to call the same Static GetInstance() method of the Singleton class. Let us run the application and 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 then 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 the code here two different threads can evaluate the condition if (instance == null) at the same time and both 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.
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, then we may end up creating 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 is not going to be created. That means when we invoke the GetInstance Method of the Singleton class, then only the Singleton Instance is going to be created. This Delay of Singleton Instance creation is called Lazy Initialization in 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 end up creating 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 Thread-Safe Singleton Design Pattern in C#. They are as follows:
- Thread-Safety Singleton Implementation using Lock.
- Implementing Thread-Safety Singleton Design Pattern using Double-Check Locking.
- Using Eager Loading to Implement Thread-Safety Singleton Design Pattern
- Using Lazy<T> Generic Class to Implement Lazy Loading in Singleton Design Pattern.
We will discuss all the above mechanisms to Implement 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 how to implement the Thread-Safe Singleton Design Pattern in C# using locks. The point that you need to remember is 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 then check 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. The most important point that you need to remember is, 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.
The above code implementation using lock solves the Singleton Design Pattern Thread-Safe issues in a multithreading environment. But the problem is that it is slow down your application as only one thread can access the GetInstance method at any given point in time. 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 or not. 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 are checking the instance two times whether it is null or not. If it is not null, then we are returning the Singleton instance. If it is null, then we are using the lock to make sure only one thread can enter the critical section. And within the lock block, again we are checking the null condition to make sure only one instance of the Singleton Class is going to 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.
In the next article, I am going to discuss the Lazy vs Eager Loading in Singleton Design Pattern in C# with Examples. Here, in this article, I try to explain How to Implement Thread-Safe Singleton Design Pattern in C# by using 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.
Awesome article, thanks
thank you, this article is very useful
Impressive
Awesome Article and all content on this website is BEST
I Love It
Very nice article and well explained.
Thanks !!
Very clear article. Simple and objetive.
Very clearly detail explanation. Thanks guy.
thank you for explanation.
Nice article. Thanks for your post
Superb and fantastic!
Good article sir
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;
}
}
read next chapter, Eager Loading
This is nothing but Eager Loading which we discussed in our next article. Please check the following link.
https://dotnettutorials.net/lesson/lazy-vs-eager-loading-chsrap/
Is it necessary to put null checking just before the line “lock (Instancelock)” ?
yes. if it not null, we do not do lock
Absolutely right. With the double null check, we can improve the performance in a multithread environment.
thanks
The best site to learn design pattern.
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