C# Singleton Design Pattern in Multi-threaded Environment
Singleton means that only the class can create only one instance. In the entire application, single instance is shared among all the threads.
The below program is thread safe in a single threaded environment.
namespace DesignPatternSingleton
{
class MyFirstDesign
{
private MyFirstDesign() {}
private static MyFirstDesign _myInstance;
public static MyFirstDesign MyInstance()
{
if(_myInstance == null)
{
_myInstance = new MyFirstDesign();
}
return _myInstance;
}
}
}
Rules
1. Single constructor – private & parameterless
a) It shouldn’t be subclassed. If it is subclassed, it will create an instance and violates the rule.
b) Only the class should be able to create instance. So the constructor is defined as private. This also means no other class can create this instance.
c) It shouldn’t have any parameter in the constructor.
2. The type of class is known up front. If the type is known during run time, it is a factory class.
3. Static variable holds the reference to the single created instance.
4. Public static method MyInstance() to get the reference to the created instance
5. Only one thread can create an instance. When the next thread tries to call the MyInstance() after first thread successfully created the instance, it will return the created instance.
What if two threads attempts to invoke MyInstance at the same time??
Multiple instances will be created which is violation against singleton pattern. To avoid this, let’s use lock.
namespace DesignPatternSingleton
{
class MyFirstDesign
{
private MyFirstDesign() {}
private static MyFirstDesign _myInstance;
private static readonly object _lock;
public static MyFirstDesign MyInstance()
{
lock(_lock)
{
if(_myInstance == null)
{
_myInstance = new MyFirstDesign();
}
}
return _myInstance;
}
}
}
At any time, only one thread enters the critical section which has lock() section. So when the next thread acquires the lock, the instance is already created so the ‘if statement’ will fail and will return the _instance.
The above program is thread safe in a multi-threaded environment.
Program.cs
using System;
using DesignPatternSingleton
Thread t1 = new Thread(() =>
{
var tInstance = MyFirstDesign.MyInstance();
}
);
Thread t2 = new Thread(() =>
{
var tInstance = MyFirstDesign.MyInstance();
}
);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
When the first thread is created, the tInstance holds id 1. When the second thread is created, the tInstance still holds id 1 because the ‘if statement’ will not be true.
namespace DesignPatternSingleton
{
sealed class MyFirstDesign
{
private MyFirstDesign() {}
public int Id { get; private set;}
private static MyFirstDesign _myInstance;
private static readonly object _lock;
public static MyFirstDesign MyInstance(int id)
{
lock(_lock)
{
if(_myInstance == null)
{
_myInstance = new MyFirstDesign();
_myInstance.Id = id;
}
}
return _myInstance;
}
}
}
The access member of MyFirstDesign is changed to sealed. This disallows to inherit from MyFirstDesign. It ensures we have only single,e instance of the class.
#CSharp