Even though Singleton is a comparatively simple pattern, there are various tradeoffs and options, depending upon the implementation.
Initial thought - 1st Implementation
public class Singleton
{
private
static Singleton
instance;
private
Singleton() { }
public static Singleton
Instance
{
get
{
if
(instance == null)
{
instance = new Singleton();
}
return
instance;
}
}
}
Advantages:
Because the instance is created
inside the Instance property
method, the class can exercise additional functionality (for example,
instantiating a subclass), even though it may introduce unwelcome dependencies.
The instantiation is not performed
until an object asks for an instance; this approach is referred to as lazy
instantiation. Lazy instantiation avoids
instantiating unnecessary singletons when the application starts.
Disadvantage:
It is not safe for multithreaded
environments. If separate threads of execution enter the Instance property method at the same time, more that one instance of the Singleton object may be created. Each thread could execute the following
statement and decide that a new instance has to be created:
if (instance == null)
Next Approach solve this problem.
Static Initialization – 2nd Implementation
public sealed class Singleton
{
private
static readonly
Singleton instance = new Singleton();
private
Singleton() { }
public static Singleton
Instance
{
get
{
return
instance;
}
}
}
In this strategy, the instance is created the first
time any member of the class is referenced. The common language runtime takes care of the variable
initialization. In addition, the variable is marked readonly,
which means that it can be assigned only during static initialization (which is
shown here) or in a class constructor.
The only potential downside of this approach is that
you have less control over the mechanics of the instantiation.
Multithreaded Singleton – 3rd Implemenation
Multithreaded Singleton – 3rd Implemenation
This approach is extension of 1st impl to make is thread
safe; coz its impossible to overcome the limitation of 2nd impl of - less control on the instantiation.
public sealed class Singleton
{
private
static volatile
Singleton instance;
private
static object
syncRoot = new Object();
private
Singleton() { }
public static Singleton
Instance
{
get
{
if
(instance == null)
{
lock
(syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return
instance;
}
}
}
This approach ensures that only one instance is created
and only when the instance is needed. Also, the variable is declared to be volatile to ensure that assignment to the instance variable completes
before the instance variable can be accessed. Lastly, this approach uses a syncRoot instance to lock on, rather than locking on the type itself, to
avoid deadlocks.