Singleton Pattern - 5 Implementations of
5 Implementations of Singleton Pattern
This article introduces singleton design pattern and
its 5 implementation variations (with C#).
Problem
At most one instance of a class must be created in an application.
At most one instance of a class must be created in an application.
Solution
That class (singleton) is defined including its own instance, and the constructor must be private.
That class (singleton) is defined including its own instance, and the constructor must be private.
Implementations
1. Lazy
initialization, non-thread safe: This is the classical version, bot it's not
thread safe. If more than one thread attempts to access instance at the same
time, more than one instance may be created.
public
class Singleton
{
private static Singleton instance = null;
public
static Singleton
Instance() {
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
private Singleton() {}
}
2. Non-lazy initialization, thread safe: This is the simplest thread safe version,
but it does not support lazy initialization.
public
class Singleton
{
private readonly static Singleton instance = new Singleton();
public static Singleton Instance()
{
return instance;
}
private Singleton() {}
}
3. Lazy initialization, thread safe: This version supports both properties, but
has performance problems. Once a thread uses singleton instance, the others
have to wait because of lock.
public
class Singleton
{
private static Singleton instance =
null;
private static readonly object lockObj = new object();
private static readonly object lockObj = new object();
public static Singleton Instance()
{
lock (lockObj) {
lock (lockObj) {
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
private Singleton() {}
}
4. Double-check locking: An improved version of the third
solution. Two null controls prevent lock waits for most time, but not always.
Also, it does not work properly for Java because of Java memory management
approach.
public class Singleton {
private static Singleton instance = null;
private static object lockObj = new object();
private static object lockObj = new object();
public static Singleton Instance()
{
if (instance == null) {
lock (lockObj) {
if (instance == null) {
lock (lockObj) {
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
return instance;
}
private Singleton() {}
}
5. Nested initialization: A nested class is used for lazy
initialization. This version is also thread safe, but a bit complex. For most
situations, solutions 2 or 4 will be suitable according to performance
parameters.
public class Singleton {
public static Singleton Instance()
{
return Nested.instance;
}
private Singleton() {}
class Nested {
static Nested() {}
internal static readonly Singleton instance = new Singleton();
}
class Nested {
static Nested() {}
internal static readonly Singleton instance = new Singleton();
}
}
Usage:
public static void Main(string[] args)
{
Singleton instance = Singleton.Instance();
}
Comments