Introduction to Singleton Design Pattern
“Only one instance of the class per container”
Singleton Pattern belongs to Creational Design Pattern. In this article, we will learn about the Singleton design pattern’s concepts, different approaches to apply it, and some best practices for using Singleton.
The singleton pattern limits the number of times a class can be instantiated and ensures that only one instance of the class exists in the container( Java virtual machine in Java is an example of a container here). To access the instance of the singleton class, the singleton class provide a global access point.
singleton pattern is often used for logging, caching, and thread pools etc. Also, other design patterns like Abstract Factory, Builder, Prototype, Facade uses Singleton.
You may find several approaches to implement Singleton on the internet if you search.
- Eager Initialization Method.
- Lazy Initialization Method
- Thread Safe Singleton Method.
- Double Lock Method.
- Lazy Load Method.
- Static Block Initialization Method.
We don’t, however, require all of them. Let’s take a look at the ones that matter. For you to get an idea, I’ve explained the Eager Initialization Method, Lazy Initialization, Static block initialization and Double Lock Singleton.
Even though there are many approaches we have the following in common.
- To prevent other classes from instantiating the class, it has a private constructor.
- The only instance of the class has a private static variable of the same class.
- This is the global access point to access the instance of the singleton class (it is a public static method that returns the instance of the class).
1. Eager Initialization
This is the simplest and easiest way to create a singleton class. According to this implementation, an instance of a singleton class is created by JVM when the class is loaded into the memory.
This method is good to use
- if the application will always use an instance of this class.
- if your singleton class is not using a lot of resources
(Since Instance is created whether an application uses it or not).
Even though there are some advantages like simple and easy implementation. There are disadvantages like resource leakage because an instance is always created.
2. Static block initialization
Static block initialization is very similar to Eager initialization. The only difference is We have exception handling here because we do the object creation in a static block.
Note: Both eager initialization and static block initialization creates the instance even before it’s being used.
3. Lazy initialization
In this implementation, an object is created only when necessary (So the resource wastage is prevented).
getInstance()
method is implemented to return an instance. There’s a null check. if the object hasn’t been created yet, create it; otherwise, return the already created object. Because an object is created within a method, it is ensured that it will not be created until it is required. No one can directly access the instance because it is kept private.
Multiple threads can break the singleton property by accessing the get instance method at the same time and creating multiple objects, therefore it can only be used in a single-threaded environment.
4. Double-checking Singleton
The way to implement a thread-safe singleton is by using double-checking. This is also called double locking.
Double-checking:
Let’s assume, a thread comes until the if condition block (line 19) and checks if instance
is null. So, since this is the 1st time this method is called it’s null. So thread 1 will go ahead and will try to execute this instance = new ThreadSafeSingleton();
(line 22). Meanwhile, thread 2 comes into the same if condition block and check if the instance
is null. This happens while the instance is being created (So still not created). So, the second thread also will go into the if condition block. So, this is not thread-safe. This is an edge case but it’s possible. Therefore we use synchronized
(line 20). So now even the 2nd thread can’t come in because with synchronized
it’s been locked.
Here is the implementation of the double-checking singleton class.
Output:
So if you run this you will see the same result because it returns the same instance.
Note: Some developers use the synchronized keyword at the method level. This is something that should not be done. Because when you use synchronized keyword in block-level it will block whole the method and will reduce the performance.
If you would like to know how Singleton is implemented, please check out my repository.