Singelton pattern in one of the most commonly used and talked about design pattern. Many appreciates it usefulness and many advocate against it. In this post we are not going to discuss all that but will concentrate on its implementation in c#.
Type:
It is a creational design pattern.
Intent:
It ensures that only one instance of the class exists.
Usage:
It is generally used when only one instance of a class is required. Thus, it can be seen to be used in logging frameworks, configuration objects etc.
The ownership of instance creation lies with the class itself. This is because we can not ensure that only one instance will ever exists for the class if the responsibility lies with someone else.
The class will instantiate the object when it will be used for the first time. This also ensures lazy initialization.
Point to consider:
Singelton object is mostly made accessible globally and thus being abused by being used as global variable. We must keep in mind that not only the singelton object but the whole object graph associated to it (which can be traversed through it) becomes global. Though most of us will say no to using global variables but will readily say yes to singeltons.
Simple Implementation:
In our SimpleSingelton class we have created a private constructor. This will ensure that no one else can instantiate SimpleSingelton by calling its constructor.
We have also create a private data member of type SimpleSingelton. This will hold the lone instance of SimpleSingelton. We have marked it static because we will access it from static members (property or method).
We have created a static property which will check if _instance is null or not. If it is null it will instantiate it and then return the _instance.
This implementation looks promising but it is not thread safe. In a multi-threaded scenario two threads can check for the nullability of _instance almost at the same time and thus can create two instances of SimpleSingelton as both will find _instance null.
Partially Thread Safe Implementation
In our PartiallyThreadSafeSingelton class we have marked the _instance as volatile this means that the most up-to date value of _instance will be used and the value will be requested every time we will use _instance although in the previous statements _instance value would have been retrieved.
In our getter for CurrentInstance we have use a lock. This will ensure that only one thread will create an instance at a time. Wait!!! But, multiple threads can check for nullability simulatneously and then one thread can wait for the other to create instance and release lock. Then it will also create an instance.
What if we check for nullability just before instantiating? Yes, we should.
Process intensive Thread Safe Implementation
It is process intensive to acquire a lock every time. As the instantiation will happen only once. Thus we can change our implementation a bit and can check for nullability one more time but before acquiring lock.
Thread Safe Implementation
In future posts we will discuss more about singelton and its usage.
Type:
It is a creational design pattern.
Intent:
It ensures that only one instance of the class exists.
Usage:
It is generally used when only one instance of a class is required. Thus, it can be seen to be used in logging frameworks, configuration objects etc.
The ownership of instance creation lies with the class itself. This is because we can not ensure that only one instance will ever exists for the class if the responsibility lies with someone else.
The class will instantiate the object when it will be used for the first time. This also ensures lazy initialization.
Point to consider:
Singelton object is mostly made accessible globally and thus being abused by being used as global variable. We must keep in mind that not only the singelton object but the whole object graph associated to it (which can be traversed through it) becomes global. Though most of us will say no to using global variables but will readily say yes to singeltons.
Simple Implementation:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PlayingWithSingelton
{
public class SimpleSingelton
{
private static SimpleSingelton _instance;
private SimpleSingelton()
{
}
public static SimpleSingelton CurrentInstance
{
get
{
if(_instance == null)
{
_instance = new SimpleSingelton();
}
return _instance;
}
}
public void Print()
{
Console.WriteLine(this.GetHashCode());
}
}
}
In our SimpleSingelton class we have created a private constructor. This will ensure that no one else can instantiate SimpleSingelton by calling its constructor.
We have also create a private data member of type SimpleSingelton. This will hold the lone instance of SimpleSingelton. We have marked it static because we will access it from static members (property or method).
We have created a static property which will check if _instance is null or not. If it is null it will instantiate it and then return the _instance.
This implementation looks promising but it is not thread safe. In a multi-threaded scenario two threads can check for the nullability of _instance almost at the same time and thus can create two instances of SimpleSingelton as both will find _instance null.
Partially Thread Safe Implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace PlayingWithSingelton
{
public class PartiallyThreadSafeSingelton
{
private static volatile PartiallyThreadSafeSingelton _instance;
private static readonly Object Locker = new object();
private PartiallyThreadSafeSingelton()
{
}
public static PartiallyThreadSafeSingelton CurrentInstance
{
get
{
if(_instance == null)
{
lock (Locker)
{
_instance = new PartiallyThreadSafeSingelton();
}
}
return _instance;
}
}
}
}
In our PartiallyThreadSafeSingelton class we have marked the _instance as volatile this means that the most up-to date value of _instance will be used and the value will be requested every time we will use _instance although in the previous statements _instance value would have been retrieved.
In our getter for CurrentInstance we have use a lock. This will ensure that only one thread will create an instance at a time. Wait!!! But, multiple threads can check for nullability simulatneously and then one thread can wait for the other to create instance and release lock. Then it will also create an instance.
What if we check for nullability just before instantiating? Yes, we should.
Process intensive Thread Safe Implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PlayingWithSingelton
{
public class ProcessIntensiveThreadSafeSingelton
{
private static volatile ProcessIntensiveThreadSafeSingelton _instance;
private static readonly Object Locker = new object();
private ProcessIntensiveThreadSafeSingelton()
{
}
public static ProcessIntensiveThreadSafeSingelton CurrentInstance
{
get
{
lock (Locker)
{
if (_instance == null)
_instance = new ProcessIntensiveThreadSafeSingelton();
}
return _instance;
}
}
}
}
It is process intensive to acquire a lock every time. As the instantiation will happen only once. Thus we can change our implementation a bit and can check for nullability one more time but before acquiring lock.
Thread Safe Implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PlayingWithSingelton
{
public class ThreadSafeSingelton
{
private static volatile ThreadSafeSingelton _instance;
private static readonly Object Locker = new object();
private ThreadSafeSingelton()
{
}
public static ThreadSafeSingelton CurrentInstance
{
get
{
if (_instance == null)
{
lock (Locker)
{
if (_instance == null)
_instance = new ThreadSafeSingelton();
}
}
return _instance;
}
}
}
}
In future posts we will discuss more about singelton and its usage.
Comments
Post a Comment