Introduction
Gang of Four describe 23 design pattern which help to solve the software design problem. Singleton is one of them.Description
Singleton design pattern comes under Creational design pattern.Singleton design pattern allows to create only one object for a class.Singleton-Design-Pattern |
Lets create a sample singleton class and see how it looks like.
class SingleTonClass
{
public static int count = 0;
public static readonly SingleTonClass Instance = new SingleTonClass();
private static SingleTonClass _EmpSal;
private SingleTonClass()
{
count++;
Console.WriteLine("Counter = : " + count);
}
public static SingleTonClass EmpSal
{
get
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
return _EmpSal;
}
}
}
{
public static int count = 0;
public static readonly SingleTonClass Instance = new SingleTonClass();
private static SingleTonClass _EmpSal;
private SingleTonClass()
{
count++;
Console.WriteLine("Counter = : " + count);
}
public static SingleTonClass EmpSal
{
get
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
return _EmpSal;
}
}
}
See the above code. We created a simple class called "SingleTonClass". This class uses 3 important keyword which makes the class singleton.
- Sealed - Helps to restrict the Inheritance.
- Private Constructor- Helps to restrict the object creation.
- Static-This will create static method.
The above code is not thread safe.
Lets understand Why?
When we use multi threaded application then the counter value becomes > 1 in private constructor, which violate the Singleton Design Pattern(Singleton allows only one object for a class).
Lets see the below example with multi-thread application.
class SingleTonClass
{
public static int count = 0;
public static readonly SingleTonClass Instance = new SingleTonClass();
private static SingleTonClass _EmpSal;
private SingleTonClass()
{
count++;
Console.WriteLine("Counter = : " + count);
}
public static SingleTonClass EmpSal
{
get
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
return _EmpSal;
}
}
public string Empsalary()
{
return "100000";
}
}
public class MainClass
{
public static void Main()
{
Thread th = new Thread(TempEmpsal);
th.Start();
Thread th1 = new Thread(permantEmpsal);
th1.Start();
//Console.WriteLine(SingleTonClass.EmpSal.Empsalary());
Console.Read();
}
public static void permantEmpsal()
{
SingleTonClass.EmpSal.Empsalary();
}
public static void TempEmpsal()
{
SingleTonClass.EmpSal.Empsalary();
}
}
{
public static int count = 0;
public static readonly SingleTonClass Instance = new SingleTonClass();
private static SingleTonClass _EmpSal;
private SingleTonClass()
{
count++;
Console.WriteLine("Counter = : " + count);
}
public static SingleTonClass EmpSal
{
get
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
return _EmpSal;
}
}
public string Empsalary()
{
return "100000";
}
}
public class MainClass
{
public static void Main()
{
Thread th = new Thread(TempEmpsal);
th.Start();
Thread th1 = new Thread(permantEmpsal);
th1.Start();
//Console.WriteLine(SingleTonClass.EmpSal.Empsalary());
Console.Read();
}
public static void permantEmpsal()
{
SingleTonClass.EmpSal.Empsalary();
}
public static void TempEmpsal()
{
SingleTonClass.EmpSal.Empsalary();
}
}
OutPut
This is the reason why the above code is not thread safe.
Then how can we make singleton class thread safe???
The Solution is Thread Synchronization. Using this we can lock single thread at a time. So using this technique we can make the application thread safe.
We need to change the EmpSal Property as below.
public static SingleTonClass EmpSal
{
get
{
lock (_EmpSal) //added this section
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
return _EmpSal;
}
}
}
After changing the code see the below output.{
get
{
lock (_EmpSal) //added this section
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
return _EmpSal;
}
}
}
One more problem may occur , as our application always keep on locking every-time it may slow down and show performance problem.
So we should use NULL check before the LOCK so that application not LOCK every-time whenever it comes to the property.
We can revised the code as below.
Multi-threading with Thread Lock
public static SingleTonClass EmpSal
{
get
{
if (_EmpSal == null)
{
lock (_EmpSal)
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
}
}
return _EmpSal;
}
}
So the Complete code which include thread safe and Performance improvement as below.{
get
{
if (_EmpSal == null)
{
lock (_EmpSal)
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
}
}
return _EmpSal;
}
}
class SingleTonClass
{
public static int count = 0;
public static readonly SingleTonClass Instance = new SingleTonClass();
private static SingleTonClass _EmpSal;
private SingleTonClass()
{
count++;
Console.WriteLine("Counter = : " + count);
}
public static SingleTonClass EmpSal
{
get
{
if (_EmpSal == null)
{
lock (_EmpSal)
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
}
}
return _EmpSal;
}
}
public string Empsalary()
{
return "100000";
}
}
public class MainClass
{
public static void Main()
{
Thread th = new Thread(TempEmpsal);
th.Start();
Thread th1 = new Thread(permantEmpsal);
th1.Start();
//Console.WriteLine(SingleTonClass.EmpSal.Empsalary());
Console.Read();
}
public static void permantEmpsal()
{
SingleTonClass.EmpSal.Empsalary();
}
public static void TempEmpsal()
{
SingleTonClass.EmpSal.Empsalary();
}
}
{
public static int count = 0;
public static readonly SingleTonClass Instance = new SingleTonClass();
private static SingleTonClass _EmpSal;
private SingleTonClass()
{
count++;
Console.WriteLine("Counter = : " + count);
}
public static SingleTonClass EmpSal
{
get
{
if (_EmpSal == null)
{
lock (_EmpSal)
{
if (_EmpSal == null)
_EmpSal = new SingleTonClass();
}
}
return _EmpSal;
}
}
public string Empsalary()
{
return "100000";
}
}
public class MainClass
{
public static void Main()
{
Thread th = new Thread(TempEmpsal);
th.Start();
Thread th1 = new Thread(permantEmpsal);
th1.Start();
//Console.WriteLine(SingleTonClass.EmpSal.Empsalary());
Console.Read();
}
public static void permantEmpsal()
{
SingleTonClass.EmpSal.Empsalary();
}
public static void TempEmpsal()
{
SingleTonClass.EmpSal.Empsalary();
}
}
Things to Remember
- Allows only single object of the class.
- Difficult for unit testing.
Thanks....................