JAVA Singleton Design Pattern
Introduction
Ensuring that only one class instance exists can be crucial in software development. The Singleton Pattern is a widely used design pattern in Java that restricts the instantiation of a class to a single object while providing a global access point to it.
From database connections to logging frameworks, the Singleton pattern plays a vital role in ensuring controlled access to shared resources. In this article, we’ll explore the concept, implementation, and best practices of the Singleton pattern in Java.
Let's understand with an example:
Suppose we have one Browser class which we want to implement with the Singleton pattern. We need to follow the below 3 points -
package SingletonPattern;
public class Browser {
private static Browser browser;
private Browser() {};
public static Browser getInstance() {
if (browser == null) {
browser = new Browser();}
return browser;
}
public void browserInfoMethod() {
System.out.println("Browser Info");
}}
Create another test class i.e. TestBrowser.java class
Now, when we try to create the object of the Browser class, it displays an error like the one above because we have made the constructor of the Browser class private. We can only access the static methods of the Browser class, such as the getInstance() method, and this method is made static, so we can call the method in the TestBrowser class with its class name Browser.getInstance().
getInstance() method says that if the value of the Browser instance is null, then create an object of the Browser class, and return the browser reference. Then we can access the public method of the Browser class as below
The objective of Singleton Pattern is to create an object or do instantiation only once.
Use of Singleton Pattern in Multi-Threading environment.
Suppose we have 3 threads T1, T2, and T3. T1 goes to getInstance method and initially there is no instantiation of Browser class so browser reference is null and it will go inside the if block and create the Browser class object. Now, second thread T2 will come and there is already an object created, and so browser ref is not null and it will return the copy of the first browser reference. And the same happens with the third thread, i.e., the same browser reference will be given to any number of threads accessing the Browser class.
But we have to do a proper thread management, i.e., to achieve thread safety so that simultaneously all threads are not accessing the Browser static method. We use synchronized keyword with static getInstance() as below. This will introduce proper locking, when T1 uses getInstance(), it will lock the method and once done it will release the lock only then T2 can use getInstance() method lock it and release it, in the same way each thread will access the getInstance() method with proper lock and release.
Now, again we can face Performance Overhead issue in multi-threading environment as all threads are running sequentially. So instead of using the synchronized keyword, we can optimize our code by implementing double check synchronization or double check instantiation.
Let's see how we can optimize our code.
All Threads T1, T2, and T3 can access the getInstance method simultaneously. T1 checks the outer check if block and creates the object, then T2 approach will not enter the outer check as browser ref is not null and will return the copy of browser ref created by T1. Any number of Thread approaches, but will work in the same way.
So in this way we are having a good code optimization and we are creating only a single object and achieving the Singleton Pattern for our Browser class.
Let's understand with an example, how multiple threads are accessing the single object of the singleton Browser class.
Added log '' ''to show that the first thread creates the reference and other threads just use the same browser reference copy.