Singleton Design Pattern in Java

Narendra Koli
Javarevisited
Published in
6 min readMar 9, 2024

Singleton Design Pattern: Embracing the Art of Uniqueness

Curious Coder: Can you please review my pull request?

Guiding Mentor: Yes, I will take a look.

A few moments later:

Guiding Mentor: I have a suggestion. You are creating a class called ApplicationConfiguration, which provides configuration details to various other classes through its methods. You can use the Singleton design pattern to create this class.

Curious Coder: but why do we need just a single object?

Guiding Mentor: Let me explain it through a simple example.

See the example class below:

For simplicity, we will be using the main method to illustrate how many objects are getting created

Curious Coder: I got you, but how can I restrict how many objects are being created?

Guiding Mentor: You can, but you must make your constructor private.

Curious Coder: How will I create the class object if the constructor is private?

Guiding Mentor: Let me tell you — you can make the constructor private and have a static method to return the object of the same class. This method must be called every time an object is created. You can add logic here to prevent creating a new object if it’s already created. I would like you to come up with a solution for this, and then we will rectify any issues. Feel free to ask any questions you have.

Curious Coder: Good idea. I will write some code and come back to you.

A few moments later:

Curious Coder: See what I have implemented; please take a look.

Guiding Mentor: That looks good, but do you see any problem with this code?

Curious Coder: I don’t see any problem.

Guiding Mentor: You create a static class object, which is initialized when the JVM loads the class in memory. So, it is a waste of memory if you don’t need to create an object, but the class is loaded into memory.

Curious Coder: Can you give me an example?

Guiding Mentor: Yes. Let’s have a look at the code below. (I am modifying your code above a little bit to demonstrate this)

The constructor is called even when we are not calling the class’s getInstance method. The JVM loads that class while accessing a static field, which is initialized during class loading.

Curious Coder: Yes, that is a problem. Let me come back to you.

A few moments later:

Curious Coder: How about this?

Guiding Mentor: Yeah, that looks good now. An object is created only when someone calls the getInstance method.

But there is one catch — will this class be used by multiple other classes where multiple threads might try to access getInstance simultaneously?

Curious Coder: It’s possible, but what is the issue?

Guiding Mentor: If multiple threads try to access the getInstance method, see the scenario below where it would fail.

I created two threads to simulate the behavior that would happen when two threads try to gain access to the getInstance method.

Curious Coder: Got it; I will come back to you again.

A few moments later:

Guiding Mentor: You synchronized the getInstance method so that only one thread can access it at a time.

Curious Coder: Yes, but this could cause performance issues as only one thread can enter the method. In our situation, we are not expecting this to happen every time but rather for the first time while creating an object when it’s not present. Only then do we want to do that, but I don’t know what we can do here.

Guiding Mentor: You are correct; use double-check locking.

Curious Coder: It sounds interesting, but I don’t know what it is.

Guiding Mentor: Double-checked locking attempts to minimize this overhead by first checking if the object has already been created without acquiring a lock. If it hasn’t, a lock is acquired, and another check is performed to ensure no other thread has created the object. If not, the object is created. This way, the lock is only acquired when necessary. Also, you must make the field volatile so every thread reads its value from memory instead of cache.

Curious Coder: Wow, that looks good.

Let’s take a similar situation where two threads enter the if block. Now, we are using class-level locking, so only one thread can enter at a time. So, the first thread will end up creating an object and coming out of the synchronized block, and then the second thread will go into the block and not create an object because the first one has already created the object.

Guiding Mentor: You are correct.

Curious Coder: That’s Great. Please tell me where we should use it and where we should not.

Guiding Mentor: Sure.

Where to use the Singleton design pattern:

  • Global State Management: Use Singleton to manage a global state that needs to be consistently accessed by various parts of the application.
  • Database Connections: For applications that require a single shared connection to a database to avoid the overhead of establishing multiple connections.
  • Configuration Settings: Singleton is suitable for loading and accessing configuration settings that remain constant throughout the application’s lifecycle.
  • Logging: Implement Singleton for logging mechanisms in which different parts of the application write to a single log file.
  • Caching: Singleton can be used for caching resources, like configurations or images, ensuring only one copy in memory to improve performance.

Where not to use the Singleton design pattern:

  • Scalability Concerns: Avoid Singleton in scenarios where scalability is a concern, as it introduces a global state that can lead to bottlenecks in multi-threaded environments.
  • Testing Challenges: Singleton can make unit testing difficult because it introduces a global state into an application, making tests potentially affect each other.
  • Flexibility and Evolution: Do not use Singleton when you anticipate that the single instance requirement might change, as it can lead to significant refactoring.
  • Misuse in Object-Oriented Design: Avoid using Singleton to provide a global access point for something that doesn’t strictly require a single instance, as it may encourage poor design practices.
  • Dependency Injection Conflicts: In environments where dependency injection is heavily used for managing dependencies, Singleton can conflict with the DI container’s ability to manage object lifecycles.

A Singleton pattern can be implemented in many ways, but our main goal was to understand how to create a thread-safe Singleton design pattern and what points to consider while writing code for it.

Curious Coder: Great. Thank you so much for helping me learn the Singleton design pattern today. 😊

Guiding Mentor: You’re welcome. 😊

Curious Coder: Now, Can you approve my pull request? 😉

Guiding Mentor: Approved.

Curious Coder: Thanks once again.

Complete Java Code: Double check locking implementation

public class SingletonDesignPatternExample {

public static void main(String[] args) {

ApplicationConfiguration object1 = ApplicationConfiguration.getInstance();
ApplicationConfiguration object2 = ApplicationConfiguration.getInstance();

System.out.println("Object 1 address: " + object1);
System.out.println("Object 2 address: " + object2);

if(object1 == object2){
System.out.println("Objects are same");
}
else{
System.out.println("Objects are not same");
}

}
}


// This class will have methods and additional variables which we will not be creating now for simplicity
// Assume there is one random static field that will be used to demonstrate class loading
class ApplicationConfiguration{

static String randomProperty = "randomValue";

private volatile static ApplicationConfiguration applicationConfiguration = null;

private ApplicationConfiguration(){
System.out.println("ApplicationConfiguration is being created");
}

public static ApplicationConfiguration getInstance(){

if(applicationConfiguration == null){

synchronized (ApplicationConfiguration.class){

if(applicationConfiguration == null){
applicationConfiguration = new ApplicationConfiguration();
}

}
}

return applicationConfiguration;
}

}

Thank you for dedicating a precious time to reading this blog post! 💖 🕒

--

--

Narendra Koli
Javarevisited

I am a Software Engineer who loves to write....❤️