In this post, we are going to discuss How to Implement Thread-Safe Singleton Design Pattern in C# with Examples. Please read our previous article where we discussed Singleton Design Pattern. In that post, the way we have implemented the Singleton Design Pattern is not Thread Safe in a Multithread Environment.
Understand Thread-Safe in Singleton Design Pattern in C#.
Before deep dive in to Thread-Safe Singleton Pattern, let us first see the problem that we face in a multithread environment if the Singleton Class is not Thread-Safe. Below is the Singleton Class which we have created in our last post.
/// <summary> /// Sealed class to ensure that it cannot be inherited /// </summary> public sealed class Singleton { /// <summary> /// To store the Singleton Instance /// </summary> private static Singleton instance = null; /// <summary> /// Counter value will be increment by 1 each time the object of the class is created /// </summary> private static int counter = 0; /// <summary> /// Private constructor to restrict the class to be instantiated from outside the class /// </summary> private Singleton() { counter++; Console.WriteLine("Counter Value " + counter.ToString()); } /// <summary> /// Static Method to return the Singleton Instance /// </summary> public static Singleton Instance() { if (instance == null) { instance = new Singleton(); } return instance; } /// <summary> /// Method to accessed from outside of the class by using the Singleton Instance /// </summary> /// <param name="message"></param> public void PrintDetails(string message) { Console.WriteLine(message); } }
Let’s modify the Program.cs as follows to use multithread programming. As you can see in the below code, we are using Parallel.Invoke method and call PrintCoachDetails() and PrintPlayerDetails() methods parallelly.
Parallel.Invoke(() => PrintCoachDetails(), () => PrintPlayerDetails()); Console.ReadLine(); static void PrintCoachDetails() { //Thread-1 Calling the GetInstance() Method of the Singleton class Singleton fromCoach = Singleton.Instance(); fromCoach.PrintDetails("From Coach"); } static void PrintPlayerDetails() { //At the same time, Thread-2 also Calling the GetInstance() Method of the Singleton Class Singleton fromPlayer = Singleton.Instance(); fromPlayer.PrintDetails("From Player"); }
So in above example, we are using the Parallel.Invoke method to access the Instance() Method parallelly. That means at the same time multiple threads are accessing the Instance() 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. 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.