Singleton Pattern (One of a Kind Objects)
Definition
The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.
We use the singleton pattern whenever we want everyone to use the same global resource, for example: thread pools, connection pools, caches, configs, logging objects,….
What do we want to accomplish?
Let the class manages its own instantiation
Prevent other classes (or anyone really) from creating a new instance on its own
Prevent the instantiation of an object more than once
Provide a global access point to a single instance
How to accomplish uniqueness?
The important question is “How to prevent instantiating an object more than once?”
We can always create an object by calling new which calls the constructor of that class, so first of all we need to make the constructor private to avoid instantiating an object by anyone (yes, the constructor can be private, whoever told you it’s not possible is wrong).
To call the private constructor we can either use an instance of that class (which doesn’t make sense as in order to have an object we need to instantiate it first! it’s like going in circles).
The other alternative is to use a static method (a class method). Good, but now this static method can be called multiple times which takes us back to the original problem. we need some way to know if we already created an object before.
How it Works
Here’s the typical recipe:
Make the constructor private
Declare a static variable
uniqueInstance
with the same type as the class to hold the singleton instanceDeclare a static method
getInstance()
which is the only way to instantiate an object of that classThe
getInstance
method first checks ifuniqueInstance
is null, in that case we haven’t created the instance yet so we instantiate an object through the private constructor, assign it touniqueInstance
then returns it. Otherwise, if it’s not null, then it was previously created so we only need to return it.
Note that this is lazy instantiation, if we never need the intance, it never gets created.
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() // Private constructor
public static Singleton getInstace() {
if(uniqueInstace == null)
uniqueInstance = new Singleton();
return uniqueInstance;
}
// Rest of the class
}
Class Diagram
Pretty simple, isn’t it!
Concurrency breaks it all!
Problem
Everything we’ve discussed so far works very nicely as long as we are dealing with a single thread, once multithreading enters the picture the previous scheme breaks!
Wait, our main goal is to share a single instance or a global resource that everyone can access, why is concurrency a problem now?
Even if we assume for now that all operations on the singleton object are thread safe, we still have a serious problem…the instantiation itself!
In particular, a race condition can happen in the getInstance
method, which may lead to instantiating the object more than once!
Solution
In order to prevent this race condition, we need to lock the code which can be accessed concurrently by multiple threads (the critical section). In particular, we need to make sure that only one thread can access the getInstance
method at a time.
public class Singleton {
private static Singleton uniqueInstance;
private Singleton(); // Private constructor
private Mutex mutx; // Lock (Language specific)
public static Singleton getInstace() {
mutx.lock();
if(uniqueInstace == null)
uniqueInstance = new Singleton();
mutx.unlock();
return uniqueInstance;
}
// Rest of the class
}
Optimized Solution
While the previous solution is correct, it introduces much overhead. Always remember that synchronization and locking is not free!
Note that the only time locking is relevant is the first time through this method, once the object is instantiating, it’s no longer required.
To illustrate more, what we wish to prevent is the following scenario: two (or more) threads read the value of uniqueInstance
at the same time and find it null, so both create a new object and we end up with two (or more) instances.
If uniqueInstance
is not null then we can return it immediately no need to lock, otherwise we lock and proceed as previously. Note that we still need to check again if uniqueInstance
is null inside the lock, if we didn’t we may still end up with more than one instance. So although this seems like redundant checking, it’s essential.
Hence, a slight rearrange of the code makes it much more efficient!
public static Singleton getInstace() {
if(uniqueInstace != null)
return uniqueInstance;
mutx.lock();
if(uniqueInstace == null)
uniqueInstance = new Singleton();
mutx.unlock();
return uniqueInstance;
}
or equivalently,
public static Singleton getInstace() {
if(uniqueInstace == null) {
mutx.lock();
if(uniqueInstace == null)
uniqueInstance = new Singleton();
mutx.unlock();
}
return uniqueInstance;
}
Language Implementation Notes
In c++, in addition to declaring the constructor as private, we also need to delete the copy constructor and assignment operator to prevent copying the object.
Singleton(Singleton const&) = delete; void operator=(Singleton const&) = delete;
Golang has its unique way to implement singleton pattern using
sync.Once
which takes care of concurrency and other performance issues for you making it very convenient to use.package singleton import "sync" type Singleton struct{} var instance *Singleton var once sync.Once func GetInstance() *Singleton { once.Do(func() { instance = &Singleton{} }) return instance }
For some languages, the singleton patterns cannot be strictly enforced and we have to depend on proper use. For example, go doesn’t have the concept of access modifiers, so there is no way to prevent anyone from instantiating an object.
Why Not Use Global Variables?
A global variable is initialized only once at program start and this is thread safe in most languages, so why go through all that hassle where we can simply use global variables?
Using global variables for implementing singletons relies on convention instead of enforcing the pattern explicitly.
Global variables are initialized at program start regardless of whether they are used or not, which can lead to waste of resources, in contrast to the lazy initialization of the singleton pattern.
In some languages, the order in which global variables are initialized is not well-defined, leading to potential bugs.
So let’s face the truth, global variables are ugly and we can run into all sorts of problem quickly.