Singleton is a design pattern in which we allow a class to be instantiated only once and use again and again from entire application. In this article we will try to see different ways to create and Singleton class and pros & cons of all the ways, we will also write some code to test it, so we can understand what's going on
*1. Singleton - Not Thread Safe *:
Let's write the very basic one which a beginner can try his first singleton class, it will be sealed so no once can inherit from it, have a private constructor so instance cannot be created from outside (you can argue if it have the only private constructor then why we need the sealed, we can discuss it latter). Finally check in instance is not already created then create it and return the instance, see the code
public sealed class Singleton
{
private static Singleton _instance = null;
private Singleton() { }
public static Singleton Instance
{
get
{
if (_instance == null)
_instance = new Singleton();
return _instance;
}
}
// Methods to test will go here
}
To test this we can add a counter private variable and two methods one to Increment the counter and one to print the counter, add the following code in our Singleton class above:
private int _counter = 0;
public int Increment()
{
return _counter++;
}
public void Print()
{
Console.WriteLine("Counter Value: " + _counter.ToString());
}
Open program.cs file and add following code in Main function to test, and run the application
static void Main(string[] args)
{
Singleton.Instance.Increment();
Singleton.Instance.Increment();
Singleton.Instance.Print();
Console.ReadLine();
}
What we are trying here? We create an instance and call the Increment method to increase the counter to 1.
Then again creating and instance and calling the increment method to increase the counter, if it will create a new object then counter will be set to 1 again otherwise to 2.
Again creating an instance and calling the print method to print the counter, if new object will be created then it will print 0, otherwise it will print 2.
Run the code and we will see it print 2, means only one instance is getting created, we are good.
Heading says, Not Thread Safe, how can we test it? Change the main code to this one:
static void Main(string[] args)
{
Parallel.Invoke(
() => Singleton.Instance.Increament(),
() => Singleton.Instance.Increament(),
() => Singleton.Instance.Print()
);
Console.ReadLine();
}
All the three will try to race and create the instance at the same and will always create a new instance and print 0 (zero)
2. Singleton - Simple Thread Safe
We will create a static variable say 'objLock' of type object and lock the thread.
See the following code, in this code, it is thread safe, the thread is locked on a shared variable 'objLock' and check whether the instance has been created or not. This takes care of the memory barrier issue and ensures that only one thread will create an instance. It ensures that only one thread will create an instance, as only one thread can be in that part of the code at a time - by the time the second thread enters it,the first thread will have already created the instance, so the expression will evaluate to false.
public sealed class Singleton
{
private static Singleton _instance = null;
private static readonly object objLock = new object(); // Added new line
private int _counter = 0;
private Singleton() { }
public static Singleton Instance
{
get
{
lock (objLock) // Added new block
{
if (_instance == null)
_instance = new Singleton();
return _instance;
}
}
}
public int Increament()
{
return _counter++;
}
public void Print()
{
Console.WriteLine("Counter Value: " + _counter.ToString());
}
}
Now run the code with our previous Parallel.Invoke method and we will see it always print 2, means only one instance gets created. Unfortunately, performance suffers as a lock is acquired every time the instance is requested.
3. Singleton - Thread Safe Using Double Check Locking
It is also a thread safe and avoid locking every time, it will check if instance is not created only then lock will be placed otherwise simply return the instance previously created, change will be only in our Instance method, so here is the modified code:
public static Singleton Instance
{
get
{
if (_instance == null)
{
lock (objLock)
{
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
Run with previous Main code and check the result, it will work smooth with a better performance.
4. Singleton - Thread Safe without using locking but not lazy instantiation
A static constructor added and see the first line of code which try to create the instance.
Logic behind it, static constructors in C# are specified to execute only when an instance of the class is created or a static member is referenced, and execute only once per AppDomain. It is faster than the previous example because there is no locking mechanism.
public sealed class Singleton
{
private static readonly Singleton _instance = new Singleton();
private int _counter = 0;
static Singleton() { } // Static constructor added
private Singleton() { }
public static Singleton Instance
{
get { return _instance; }
}
// Increment and print method code removed for clarity
}
Let's say if we have any other static method inside the class, whenever we will call that method instance will be created, so it is not fully lazy singleton. Run the code and check the result.
5. Singleton - Thread Safe fully lazy instantiation
In this approach we will create a private Nested class and create the instance in this nested class. Here is the code with Nested class:
public sealed class Singleton
{
private int _counter = 0;
private Singleton() { }
public static Singleton Instance
{
get { return Nested.instance; }
}
private class Nested
{
static Nested() { }
internal static readonly Singleton instance = new Singleton();
}
// Increment and print method code removed for clarity
}
It is fully lazy, imagine the previous situation, if there is any static method in our singleton class, that will not call the instantiation of the nested class, unless we call the Instance method of our singleton class, which will create the instance and return. Since it is a static readonly so only one time will be instantiated.
If you are thinking, why it is internal
static readonly Singleton instance = new Singleton(), because nested class can access the private members of parent but reverse is not true, remove the internal and try to compile the code and you will know why it is needed.
6. Singleton - By using System.Lazy
It's simple and thread safe and fully lazy, just create the instance by using the lamda expression.
public sealed class Singleton
{
private int _counter = 0;
private static readonly Lazy<Singleton> _instance = new Lazy<Singleton>(() => new Singleton());
private Singleton() { }
public static Singleton Instance
{
get { return _instance.Value; }
}
// Increment and print method code removed for clarity
}
Run the code the test the result.
We left the part, why we need to use the sealed class when we have a private constructor.
Remove the sealed access modifier and try to inherit from Singleton class, try this (our of the Singleton class):
public class MySingleton : Singleton { }
We will get error: SingletonDemo.Singleton.Singleton() is inaccessible due to its protection level
Now move the above code inside the Singleton class and every thing will work, means anyone can override our methods, so to protect it we need to make sealed, so no once can inherit from it.
Singleton - Real time examples where we need to use
Here are some examples where we can use the singleton pattern, there are not only the case but some of them:
Benefit of Singleton Pattern
![]() |
Having 13+ years of experience in Microsoft Technologies (C#, ASP.Net, MVC and SQL Server). Worked with Metaoption LLC, for more than 9 years and still with the same company. Always ready to learn new technologies and tricks.
|
By Ali Adravi On 03 Jul, 18 Viewed: 7,222 |
In C# there are different data type and they use some default value when we declare a variable. When we define a variable of type int or Int32 say int score; so what is the value of score, will it be null or zero, in the same way if we create a variable of type string/String what value it holds... By Ali Adravi On 27 Mar 2013 Viewed: 2,623
An enumeration type (also known an enumeration or an enum) provides an efficient way to define a set of named integral constants that may be assigned to a variable to make programming clear, understandable and manageable. There are ways of using, like how to use enum in switch and case statement,... By Hamden On 27 Mar 2013 Viewed: 4,586
When we have var which dynamically holds any type or value so why we need dynamic type, what are the differences and situations where we can use dynamic rather than var, there were some question in my mind so I explored more which I want to share here. There are two things, static type and... By Nathan Armour On 26 Mar 2013 Viewed: 3,223
An array can be initialized in several ways, it can store a single value or series of values, every element must be set of same type, C# supports single-dimensional arrays, multidimensional arrays (also call rectangular array) and array-of-arrays (referred jagged arrays), let’s discuss features of... By Ali Adravi On 24 Mar 2013 Viewed: 4,409
When there was XmlDocument why we need XDocument, is there any better feature available with XDocument, answer is yes, XDocument has a number of benefits, easy to create, easy to update, easy to search, ability to use LINQ to XML, cleaner object model etc. In this post we will see some examples... By Ali Adravi On 16 Mar 2013 Viewed: 3,544