SlideShare une entreprise Scribd logo
1  sur  6
Télécharger pour lire hors ligne
Articles from Jinal Desai .NET
All About Singleton Pattern
2013-07-20 09:07:15 Jinal Desai
What is Singleton Pattern?
The Single Pattern is the simplest design pattern. Many times it’s important to have
only one instance for a particular class, for example we need to provide
configuration manager for all the configurations of our application. But, we need to
restrict instantiation of configuration manager class to only one. So only one
instance of configuration manager will serve all the requests for configuration of our
application. To better understand the scenario following is pseudo code.
if(configurationManagerInstance == null)
configurationManagerInstance = new ConfigurationManager();
return configurationManagerInstance;
Whenever any request arrives that demands configuration settings of our
application, one instance of configuration manager will serve the request. If this is
the first request it will going to instantiate the configuration manager instance
otherwise it will return already instantiated configuration manager instance.
What Singleton Pattern Ensures?
Single Pattern ensures following things.
It ensures that instance is created only once.
It ensures that instance will never be null.
It ensures that instance will be thread safe.
Instance uses little memory.
Provides lazy instantiation.
Class is freezes for sub-classing and instantiation.
Implementation of a Singleton Pattern
The implementation of a singleton pattern involves a static member inside “sealed”
public singleton class with a private constructor and a static public method
GetInstance() which returns a reference to the static member (which holds only
single instance of the class).
UML Diagram of Singleton Pattern
The GetInstance() method is responsible for returning single instance of the class. If
the static member is null it will instantiate the static member. The instantiation is
done inside the GetInstance() method thus it needs to be thread safe.
//sealed to make sure it's not inheritable
public sealed class singleton
{
//static member to ensure single placeholder for object throughout scope of the class
private static singleton instance;
//used for locking block of code
private static readonly object locker = new object();
//private constructor to restrict direct instantiation of the class
private singleton() { }
public static singleton GetInstance()
{
//synchronization lock, only one thread will enter the block
lock(locker)
{
if(instance == null)
instance = new singleton();
}
return instance;
}
/*
public void OtherMethods() { }
*/
}
When Singleton Pattern is Preferred?
Singleton is preferred over global variables because it allows lazy allocation
and instantiation. It also consumes resources only when required compare to
global variables which in many languages always consume resources even if
not required.
The other scenario where singleton pattern preferred is in case of “heavy”
objects or factories. If our object is large which takes reasonable amount of
memory we normally wish to instantiate only one object. In case of
implementing factories we also wish to provide single instance of the factory.
Why Singleton? Not Static Class
Because singleton don’t require to use the static keyword everywhere, it
preserves the conventional class approach.
Because singleton can implement interfaces or can be derived from base
classes if required.
Because singletons can be used as parameters or objects.
Examples
Load Balancer Classes
Configuration Classes
Common Shared Resource Classes (printer class, scanner class, etc)
Logger Classes (logging framework)
Factories (session factories)
DBMS classes
Implementation Scenarios
Multi-threading Implementation :
In multi-threaded usage, multiple threads are simultaneously accessing singleton
class. If the instantiation is not thread-safe then there might be the chances that two
threads holding difference instance object for same singleton class, which will spoil
the purpose of singleton pattern. So, while implementing singleton pattern it is
common practice to make the object instantiation logic thread-safe. Previous
example shows basic thread-safe implementation in csharp.
Protected Constructor :
Normally, the constructor of a singleton class implementation is private. But in
scenario where subclassing of a singleton class is needed we can keep constructor
of a singleton class as private. There are drawbacks associated with this kind of
implementation.
Protected constructor means, the class can be instantiated through calling
the constructor from another class within the same namespace. Solution to
the problem is creating separate namespace for singleton class
implementation purpose.
For using derived class, we need to change GetInstance calls from
Singleton.GetInstance() to NewSingleton.GetInstance().
Implementation Using Static Field (Early Instantiation) :
In previous code example, singleton class is instantiated in synchronized block only
when it calls GetInstance() for the first time. If we need to ensure instantiation when
the class is loaded, not when it is called first time GetInstance() method (called
Early Instantiated) then we can achieve this using static fields instantiated directly
which declared.
//sealed to make sure it's not inheritable
public sealed class singleton
{
//static member to ensure single placeholder for object throughout scope of the class
//Early Instantiation
private static singleton instance = GetInstance();
//private constructor to restrict direct instantiation of the class
private singleton() { }
//no need of synchronized block to make it thread safe
public static singleton GetInstance()
{
if(instance == null)
instance = new singleton();
return instance;
}
/*
public void OtherMethods() { }
*/
}
Double Locking Implementation (Lazy Instantiation) :
The idea behind the double is to avoid costly synchronization for every invocations of
the GetInstance() method. The cost of synchronization differs from compiler to
compiler and even as the compilers are evolved the cost of synchronization
decreases. But, it still affects performance, it still costs performance. So application
developers never want to waste processing time whenever possible. Double locking
is implementation for the same.
//sealed to make sure it's not inheritable
public sealed class singleton
{
//static member to ensure single placeholder for object throughout scope of the class
private static singleton instance;
//used for locking block of code
private static readonly object locker = new object();
//private constructor to restrict direct instantiation of the class
private singleton() { }
//synchronized block needed if instance is null
public static singleton GetInstance()
{
if(instance == null)
{
//synchronization lock, only one thread will enter the block
lock(locker)
{
//double checking for nullability of instance object
if(instance == null)
instance = new singleton();
}
}
return instance;
}
/*
public void OtherMethods() { }
*/
}
Now lets dry run the double locking algorithm.
Step 1. First thread enters the GetInstance() method.
Step 2. First thread enters the synchronized block because instance is null.
Step 3. Now second thread comes into the picture. Second thread enters the
GetInstance() method.
Step 4. Second thread tries to acquire the lock, but since the first thread holds the
lock second thread waits.
Step 5. First thread continues execution. The instance is null so it creates a
singleton object and assigns to instance variable.
Step 6. First thread exits the synchronization block and returns instance from the
GetInstance() method.
Step 7. Since synchronized block is no longer blocked by any other thread second
thread continues execution.
Step 8. Second thread acquires the synchronization lock and checks whether
instance is null or not.
Step 9. The instance is not null so rather than creating second instance created it
will return the instance already created by first thread.
(In single locking case second thread at Step 8. will found instance null and create
another instance, which would break singleton pattern)
So, this is how double locking implementation works.
Out Of Order Writes
Final scenario we discuss is out of order writes. It is basically dealt with the
synchronization between object instantiation and calling of construction of singleton
class to make instantiation complete. Let’s again dry run double locking algorithm
with some different aspect in mind.
Step 1: First thread enters GetInstance() method and found instance is null.
Step 2: First thread enters synchronization block and found again instance is null.
Step 3: Since first thread founds instance null inside the synchronization block it will
instantiate instance object, but still the constructor of Singleton class is not
executed.
Step 4: Second thread comes into the picture, and checks if instance is null.
Step 5: Since instance is already instantiated by first thread second thread found
instance not null.
Step 6: So, second thread will return instance object instantiated by first thread but it
is partially initialized Singleton object.
Step 7: First thread continues execution by completing initialization of the Singleton
object by executing it’s constructor and returns with instance object.
So, in above dry run double locking mechanism breaks. The situation here we
generated by above dry run is called out-of-order writes.
To avoid out-of-order write problem we need to introduce local variable instance1
and second synchronization block. Sample code is shown below.
//sealed to make sure it's not inheritable
public sealed class singleton
{
//static member to ensure single placeholder for object throughout scope of the class
private static singleton instance;
//used for locking first synchronization block of code
private static readonly object locker = new object();
//used for locking second synchronization block of code
private static readonly object locker1 = new object();
//private constructor to restrict direct instantiation of the class
private singleton() { }
//synchronized block needed if instance is null
public static singleton GetInstance()
{
if(instance == null)
{
//first synchronization lock, only one thread will enter the block
lock(locker)
{
Singleton instance1 = instance;
if(instance1 == null)
{
//second level synchronization lock, only one thread will enter the block
lock(locker1)
{
instance1 = new singleton();
}
instance = instance1;
}
}
}
return instance;
}
/*
public void OtherMethods() { }
*/
}
Let’s dry run above algorithm to check whether it addresses out-of-order write
scenario or not.
Step 1: First thread enters GetInstance() method.
Step 2: The instance object is null, so it enters the first synchronization block and
assign instance1 the value of instance which is null right now.
Step 3: First thread now checks the value of instance1 which is null so enters
second synchronization block and instantiate instance1 but constructor execution is
still pending execution.
Step 4: Now, second thread comes into the picture. Second thread enters into the
GetInstance method and checks whether instance is null or not.
Step 5: Since instance is still null (first thread still not assign initialized object to
instance, it’s still reference initialized object to instance1),
second thread tries to enter first synchronization block but since first thread is
holding the lock second thread not able to enter first synchronization block.
Step 6: First thread completes execution by assigning fully constructed object
instance1 to instance and leaves both synchronization blocks and returns fully
constructed instance object.
Step 7: Second thread will get the access to first synchronization block and assigns
instance object reference which is now not null to instance1.
Step 8: Now, while checking not null of instance1, second thread will found it’s not
null and already initialized. So, second thread will not enter the second
synchronization block.
Step 9: Second thread returns fully constructed instance object.
There are some optimizations also possible to the above algorithm, but this is the
basic algorithm which addresses both double-checked locking scenario as well as
out-of-order writes scenario.
References
OODesign
Double-checked locking and the Singleton pattern

Contenu connexe

Plus de jinaldesailive

Basic design pattern interview questions
Basic design pattern interview questionsBasic design pattern interview questions
Basic design pattern interview questionsjinaldesailive
 
Exam 70 480 CSS3 at Jinal Desai .NET
Exam 70 480 CSS3 at Jinal Desai .NETExam 70 480 CSS3 at Jinal Desai .NET
Exam 70 480 CSS3 at Jinal Desai .NETjinaldesailive
 
OOPS With CSharp - Jinal Desai .NET
OOPS With CSharp - Jinal Desai .NETOOPS With CSharp - Jinal Desai .NET
OOPS With CSharp - Jinal Desai .NETjinaldesailive
 
Mvc interview questions – deep dive jinal desai
Mvc interview questions – deep dive   jinal desaiMvc interview questions – deep dive   jinal desai
Mvc interview questions – deep dive jinal desaijinaldesailive
 
Software design principles - jinal desai
Software design principles - jinal desaiSoftware design principles - jinal desai
Software design principles - jinal desaijinaldesailive
 

Plus de jinaldesailive (6)

Wcf tutorials
Wcf tutorialsWcf tutorials
Wcf tutorials
 
Basic design pattern interview questions
Basic design pattern interview questionsBasic design pattern interview questions
Basic design pattern interview questions
 
Exam 70 480 CSS3 at Jinal Desai .NET
Exam 70 480 CSS3 at Jinal Desai .NETExam 70 480 CSS3 at Jinal Desai .NET
Exam 70 480 CSS3 at Jinal Desai .NET
 
OOPS With CSharp - Jinal Desai .NET
OOPS With CSharp - Jinal Desai .NETOOPS With CSharp - Jinal Desai .NET
OOPS With CSharp - Jinal Desai .NET
 
Mvc interview questions – deep dive jinal desai
Mvc interview questions – deep dive   jinal desaiMvc interview questions – deep dive   jinal desai
Mvc interview questions – deep dive jinal desai
 
Software design principles - jinal desai
Software design principles - jinal desaiSoftware design principles - jinal desai
Software design principles - jinal desai
 

Dernier

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 

Dernier (20)

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 

All about singleton pattern

  • 1. Articles from Jinal Desai .NET All About Singleton Pattern 2013-07-20 09:07:15 Jinal Desai What is Singleton Pattern? The Single Pattern is the simplest design pattern. Many times it’s important to have only one instance for a particular class, for example we need to provide configuration manager for all the configurations of our application. But, we need to restrict instantiation of configuration manager class to only one. So only one instance of configuration manager will serve all the requests for configuration of our application. To better understand the scenario following is pseudo code. if(configurationManagerInstance == null) configurationManagerInstance = new ConfigurationManager(); return configurationManagerInstance; Whenever any request arrives that demands configuration settings of our application, one instance of configuration manager will serve the request. If this is the first request it will going to instantiate the configuration manager instance otherwise it will return already instantiated configuration manager instance. What Singleton Pattern Ensures? Single Pattern ensures following things. It ensures that instance is created only once. It ensures that instance will never be null. It ensures that instance will be thread safe. Instance uses little memory. Provides lazy instantiation. Class is freezes for sub-classing and instantiation. Implementation of a Singleton Pattern The implementation of a singleton pattern involves a static member inside “sealed” public singleton class with a private constructor and a static public method GetInstance() which returns a reference to the static member (which holds only single instance of the class). UML Diagram of Singleton Pattern The GetInstance() method is responsible for returning single instance of the class. If the static member is null it will instantiate the static member. The instantiation is done inside the GetInstance() method thus it needs to be thread safe. //sealed to make sure it's not inheritable public sealed class singleton {
  • 2. //static member to ensure single placeholder for object throughout scope of the class private static singleton instance; //used for locking block of code private static readonly object locker = new object(); //private constructor to restrict direct instantiation of the class private singleton() { } public static singleton GetInstance() { //synchronization lock, only one thread will enter the block lock(locker) { if(instance == null) instance = new singleton(); } return instance; } /* public void OtherMethods() { } */ } When Singleton Pattern is Preferred? Singleton is preferred over global variables because it allows lazy allocation and instantiation. It also consumes resources only when required compare to global variables which in many languages always consume resources even if not required. The other scenario where singleton pattern preferred is in case of “heavy” objects or factories. If our object is large which takes reasonable amount of memory we normally wish to instantiate only one object. In case of implementing factories we also wish to provide single instance of the factory. Why Singleton? Not Static Class Because singleton don’t require to use the static keyword everywhere, it preserves the conventional class approach. Because singleton can implement interfaces or can be derived from base classes if required. Because singletons can be used as parameters or objects. Examples Load Balancer Classes Configuration Classes Common Shared Resource Classes (printer class, scanner class, etc) Logger Classes (logging framework) Factories (session factories) DBMS classes Implementation Scenarios Multi-threading Implementation : In multi-threaded usage, multiple threads are simultaneously accessing singleton class. If the instantiation is not thread-safe then there might be the chances that two threads holding difference instance object for same singleton class, which will spoil the purpose of singleton pattern. So, while implementing singleton pattern it is common practice to make the object instantiation logic thread-safe. Previous example shows basic thread-safe implementation in csharp. Protected Constructor : Normally, the constructor of a singleton class implementation is private. But in
  • 3. scenario where subclassing of a singleton class is needed we can keep constructor of a singleton class as private. There are drawbacks associated with this kind of implementation. Protected constructor means, the class can be instantiated through calling the constructor from another class within the same namespace. Solution to the problem is creating separate namespace for singleton class implementation purpose. For using derived class, we need to change GetInstance calls from Singleton.GetInstance() to NewSingleton.GetInstance(). Implementation Using Static Field (Early Instantiation) : In previous code example, singleton class is instantiated in synchronized block only when it calls GetInstance() for the first time. If we need to ensure instantiation when the class is loaded, not when it is called first time GetInstance() method (called Early Instantiated) then we can achieve this using static fields instantiated directly which declared. //sealed to make sure it's not inheritable public sealed class singleton { //static member to ensure single placeholder for object throughout scope of the class //Early Instantiation private static singleton instance = GetInstance(); //private constructor to restrict direct instantiation of the class private singleton() { } //no need of synchronized block to make it thread safe public static singleton GetInstance() { if(instance == null) instance = new singleton(); return instance; } /* public void OtherMethods() { } */ } Double Locking Implementation (Lazy Instantiation) : The idea behind the double is to avoid costly synchronization for every invocations of the GetInstance() method. The cost of synchronization differs from compiler to compiler and even as the compilers are evolved the cost of synchronization decreases. But, it still affects performance, it still costs performance. So application developers never want to waste processing time whenever possible. Double locking is implementation for the same. //sealed to make sure it's not inheritable public sealed class singleton { //static member to ensure single placeholder for object throughout scope of the class private static singleton instance; //used for locking block of code private static readonly object locker = new object(); //private constructor to restrict direct instantiation of the class private singleton() { } //synchronized block needed if instance is null public static singleton GetInstance() { if(instance == null) {
  • 4. //synchronization lock, only one thread will enter the block lock(locker) { //double checking for nullability of instance object if(instance == null) instance = new singleton(); } } return instance; } /* public void OtherMethods() { } */ } Now lets dry run the double locking algorithm. Step 1. First thread enters the GetInstance() method. Step 2. First thread enters the synchronized block because instance is null. Step 3. Now second thread comes into the picture. Second thread enters the GetInstance() method. Step 4. Second thread tries to acquire the lock, but since the first thread holds the lock second thread waits. Step 5. First thread continues execution. The instance is null so it creates a singleton object and assigns to instance variable. Step 6. First thread exits the synchronization block and returns instance from the GetInstance() method. Step 7. Since synchronized block is no longer blocked by any other thread second thread continues execution. Step 8. Second thread acquires the synchronization lock and checks whether instance is null or not. Step 9. The instance is not null so rather than creating second instance created it will return the instance already created by first thread. (In single locking case second thread at Step 8. will found instance null and create another instance, which would break singleton pattern) So, this is how double locking implementation works. Out Of Order Writes Final scenario we discuss is out of order writes. It is basically dealt with the synchronization between object instantiation and calling of construction of singleton class to make instantiation complete. Let’s again dry run double locking algorithm with some different aspect in mind. Step 1: First thread enters GetInstance() method and found instance is null. Step 2: First thread enters synchronization block and found again instance is null. Step 3: Since first thread founds instance null inside the synchronization block it will instantiate instance object, but still the constructor of Singleton class is not executed. Step 4: Second thread comes into the picture, and checks if instance is null. Step 5: Since instance is already instantiated by first thread second thread found instance not null. Step 6: So, second thread will return instance object instantiated by first thread but it is partially initialized Singleton object. Step 7: First thread continues execution by completing initialization of the Singleton object by executing it’s constructor and returns with instance object. So, in above dry run double locking mechanism breaks. The situation here we generated by above dry run is called out-of-order writes. To avoid out-of-order write problem we need to introduce local variable instance1 and second synchronization block. Sample code is shown below. //sealed to make sure it's not inheritable public sealed class singleton { //static member to ensure single placeholder for object throughout scope of the class
  • 5. private static singleton instance; //used for locking first synchronization block of code private static readonly object locker = new object(); //used for locking second synchronization block of code private static readonly object locker1 = new object(); //private constructor to restrict direct instantiation of the class private singleton() { } //synchronized block needed if instance is null public static singleton GetInstance() { if(instance == null) { //first synchronization lock, only one thread will enter the block lock(locker) { Singleton instance1 = instance; if(instance1 == null) { //second level synchronization lock, only one thread will enter the block lock(locker1) { instance1 = new singleton(); } instance = instance1; } } } return instance; } /* public void OtherMethods() { } */ } Let’s dry run above algorithm to check whether it addresses out-of-order write scenario or not. Step 1: First thread enters GetInstance() method. Step 2: The instance object is null, so it enters the first synchronization block and assign instance1 the value of instance which is null right now. Step 3: First thread now checks the value of instance1 which is null so enters second synchronization block and instantiate instance1 but constructor execution is still pending execution. Step 4: Now, second thread comes into the picture. Second thread enters into the GetInstance method and checks whether instance is null or not. Step 5: Since instance is still null (first thread still not assign initialized object to instance, it’s still reference initialized object to instance1), second thread tries to enter first synchronization block but since first thread is holding the lock second thread not able to enter first synchronization block. Step 6: First thread completes execution by assigning fully constructed object instance1 to instance and leaves both synchronization blocks and returns fully constructed instance object. Step 7: Second thread will get the access to first synchronization block and assigns instance object reference which is now not null to instance1. Step 8: Now, while checking not null of instance1, second thread will found it’s not null and already initialized. So, second thread will not enter the second synchronization block. Step 9: Second thread returns fully constructed instance object. There are some optimizations also possible to the above algorithm, but this is the basic algorithm which addresses both double-checked locking scenario as well as out-of-order writes scenario. References
  • 6. OODesign Double-checked locking and the Singleton pattern