Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance.
Problem
The Singleton pattern solves two problems at the same time, violating the Single Responsibility Principle:
- Ensure that a class has just a single instance.
- Provide a global access point to that instance.
Solution
All implementations of the Singleton have these two steps in common:
- Make the default constructor private, to prevent other objects from using the
new
operator with the Singleton class. - Create a static creation method that acts as a constructor. Under the hood, this method calls the private constructor to create an object and saves it in a static field. All following calls to this method return the cached object.
If your code has access to the Singleton class, then it’s able to call the Singleton’s static method. So whenever that method is called, the same object is always returned.
Singleton in Java
Naïve Singleton (single-threaded)
It’s pretty easy to implement a sloppy Singleton. You just need to hide the constructor and implement a static creation method.
Singleton.java: Singleton
1 | public final class Singleton { |
DemoSingleThread.java: Client code
1 | public class DemoSingleThread { |
OutputDemoSingleThread.txt: Execution result
1 | If you see the same value, then singleton was reused (yay!) |
Naïve Singleton (multithreaded)
The same class behaves incorrectly in a multithreaded environment. Multiple threads can call the creation method simultaneously and get several instances of Singleton class.
Singleton.java: Singleton
1 | public final class Singleton { |
DemoMultiThread.java: Client code
1 | public class DemoMultiThread { |
OutputDemoMultiThread.txt: Execution result
1 | If you see the same value, then singleton was reused (yay!) |
Thread-safe Singleton with lazy loading
To fix the problem, you have to synchronize threads during first creation of the Singleton object.
Singleton.java: Singleton
1 | public final class Singleton { |
DemoMultiThread.java: Client code
1 | public class DemoMultiThread { |
OutputDemoMultiThread.txt: Execution result
1 | If you see the same value, then singleton was reused (yay!) |