Learn the Singleton Design Pattern
This is the 2nd post in a series on design patterns.
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.
Singleton pattern provides:
- Ensure that a class has just a single instance — The most common reason for this is to control access to some shared resource like database access.
- Provide a global access point to that instance — The singleton pattern lets you access the same object from anywhere. It also protects that instance from being overwritten by other codes.
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 stood, 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.
UML Class Diagram
The Singleton class declares the static method getInstance() that returns the same instance of its own class. Singleton’s constructor should be hidden from the client code. Calling the getInstance() method should be the only way of getting the Singleton object.
Not familiar with UML Class Diagram? I have written a detailed post on the UML Class diagram.
Implementation steps:
- Add a private static (volatile for multi-threading) field to the class for storing the singleton instance.
- Declare a public static creation method for getting the singleton instance.
- Implement a lazy initialization inside the static method. It should create a new object on its first call and put it into the static field. The method should always return that instance on all subsequent calls. You need to take care of thread lock if your application is multithreaded.
- Make the constructor of the class private. The static method of the class will still be able to call the constructor, but not the other objects.
Two implementations of the Singleton design pattern are shown below — one using binary semaphore and another using synchronized.
Using Binary Semaphore
// Output on my system
pool-1-thread-2: Instance is null before acquiring semaphore
pool-1-thread-2: Semaphore acquired
pool-1-thread-1: Instance is null before acquiring semaphore
pool-1-thread-2: Instance is null after acquiring semaphore
pool-1-thread-2: Semaphore released
pool-1-thread-2: You are testing Singleton Class: 1258930662
pool-1-thread-1: Semaphore acquired
pool-1-thread-1: Semaphore released
pool-1-thread-1: You are testing Singleton Class: 1258930662
Using Synchronized
// Output on my system
pool-1-thread-2: Instance is null before synchronized
pool-1-thread-1: Instance is null before synchronized
pool-1-thread-2: Instance is null after synchronized
pool-1-thread-2: You are testing Singleton Class: 1962484795
pool-1-thread-1: You are testing Singleton Class: 1962484795
Using enum to create Singleton
Many of the problems we have discussed like worrying about synchronization and lazy loading can be solved using an enum to create your Singleton.
// Output on my system
pool-1-thread-2: You are testing Singleton Class: 1962484795
pool-1-thread-1: You are testing Singleton Class: 1962484795
Pros of Singleton design pattern
- You can be sure that a class has only a single instance.
- You gain a global access point to that instance.
- The singleton object is initialized only when it’s requested for the first time.
- Saves memory for the creation of multiple objects.
- Handles the concurrency issues in a multi-threaded environment.