What is Singleton Pattern?
The singleton pattern is a creational pattern that ensures a class has only one instance, and provides a global point of access to it.
When to use it?
Use Singleton pattern when you want to ensure only one instance of a class exists in application.
Problem
Let's try to implement our Singleton pattern.
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- Singleton class holds static variable
instance
, this is our one and only instance of Singleton class. - Constructor is declared as private so that nobody can't instantiate Singleton class except for Singleton class itself.
-
getInstance()
returns instance of Singleton class. In this code, instance gets created when it is needed, this is called lazy instantiation.
Can you spot the problem? Think what happens when we're in multithreading environment.
The problem occurs more than one thread call getInstance()
at the same time. Let's see how it occurs when we have two threads...
- Thread1 checks if instance is null or not, we haven't called
getInstance()
before, thusinstance == null
is true. - Thread2 also calls
getInstance()
and check if instance is null. Because Thread1 just entered insideif
block and didn't create object,instance
is still null. - Thread1 instantiates Singleton class with
new
keyword. - Thread2 also instantiates Singleton class.
We now have two Singleton objects, which is not desired.
Such a situation is called race condition, where multiple threads attempt to access to shared resources at the same time but its outcome is indeterministic.
Solution 1
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Solution is just adding synchronized
keyword to getInstance()
. synchronized
keyword can ensure only one thread can enter the method at the time and other threads wait their turn.
This works fine but synchronization is expensive. synchronization is only needed when getInstance()
is called for the first time since once we get instance of Singleton, getInstance()
won't enter if
block and just return an object that already has been created. After the first time through, synchronization is totally unneeded overhead.
Solution 2
We can implement eager instantiation Singleton if our application always creates and uses an instance of Singleton.
public class Singleton {
// Create an instance when Singleton class is loaded by JVM
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
// instance has already been created
return instance;
}
}
Solution 3
if performance of getInstance() is an issue (like we pointed out in Solution 1), we can implement double-checked locking Singleton.
As name indicates, this implementation does null-check for our instance twice.
- First check: if instance is null, it enters the block.
- Synchronization: lock on Singleton class object (Class object is a runtime representation of the class), this ensures only one thread at a time executes the synchronized block. The synchronized block represents critical section.
- Second check: this check can't occur at a time because of synchronization.
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) { // First check
synchronized (Singleton.class) { // Synchronization
if (instance == null) { // Second check
instance = new Singleton();
}
}
}
return instance;
}
}
Solution 4
Singleton sounds simple but it has many things we have to consider such as synchronization, class loading, reflection and serialization/deserialization issues. Is there any better implementation that resolves these issues? Yes, enum provides simple implementation and resolves all the issues above.
public enum Singleton {
INSTANCE;
}
We don't need to write our own private constructor because JVM will instantiate our INSTANCE automatically.
Structure
Pitfalls
- Singleton violates the single responsibility principle as it does two jobs, ensuring only one instance exists & providing a global access point to that instance.
You can check all the design pattern implementations here.
GitHub Repository
P.S.
I'm new to write tech blog, if you have advice to improve my writing, or have any confusing point, please leave a comment!
Thank you for reading :)
Top comments (0)