Which implementation of Singleton Pattern do I need?

Furkan Kaya
4 min readJan 16, 2022
Image from: refactoring.guru

Singleton pattern is a creational design pattern that lets you ensure that a class has only one instance and provides a global access point to this instance. By looking at this definition, we make sure that Singleton Pattern violates Single Responsibility Principle. Anyway, that’s not our topic right now. Let’s implement a singleton pattern in the simplest way just by looking at this definition.

Did this simple implementation meet both requirements in the Singleton Pattern definition? Let’s examine.

When we need an instance of this class, we will call the getInstance method. If we are calling this method for the first time, it will create a new BasicSingleton object and return it, since the static instance variable will be null. Also, the constructor is private, we will not be able to create a BasicSingleton object with the new keyword. So far everything looks good. We even do lazy initialization, so cool. But what if more than one thread calls the getInstance method at the same time and they both pass the null condition and create two separate instance object. At this point, we’re crushing singleton pattern first rule. One and only one instance at a time.

Here’s what we learned from our first implementation

If we are developing a single-threaded application it makes sense to use it. Now let’s think about what we can do to use Singleton in multi-threaded applications.

We just added the synchronized keyword to the getInstance method. In this way, we have ensured that every thread that calls the getInstance method will wait for its turn and that two threads will not run in this method at the same time. So our method became thread-safe. What if the getInstance method of this class is called in high traffic in our application. We will keep the threads waiting for the problem that we may face only in the first initialization of the instance.

Here’s what we learned from our second implementation

We can use this if we are working in a multi-threaded application and we don’t want to get a high traffic getInstance call in my class that we want to be a singleton. It’s a very simple and readable implementation that meets Singleton Pattern needs. Now let’s see what kind of improvement we can do for high traffic.

WHAT? Static initializer… How could we not think of that? Instance being eagerly initialized and this instance is returned in every getInstance method call. We were able to make it thread-safe without using synchronized.

Here’s what we learned from our third implementation

It’s a great solution if it won’t be a problem to create this instance when the class is loaded, and if it will be used later. What if we don’t want this instance to be initialized when the class is loaded. Maybe our application will not use this instance. Let’s take a look at what we can do about this situation.

With double-checked locking, we first check if there is an instance and if it doesn’t, we perform synchronization. In other words, we do the synchronization operation only during the creation phase of the instance. volatile keyword is used as an indicator to JVM and thread that do not cache value of this variable and always read it from main memory. With this keyword, we ensure that it is thread-safe.

Here’s what we learned from our fourth implementation

If performance is an issue with your use of the getInstance method, this implementation is for you. But don’t you think it looks a bit complicated? Let’s see how we can implement the Singleton more simply.

Simplest Singleton implementation ever, right? But how? Where is the private constructor? In Java, enums have an implicit empty private constructor. When your code first accesses INSTANCE, the class EnumBasedSingleton will be loaded and initialized by the JVM.

Here’s what we learned from our fifth implementation

You can implement Singleton pattern in a very simple and thread-safe way using enums.

As we conclude our article, we can summarize as follows: If we think that the solution offered by Singleton is suitable for our problem, we can choose an implementation by considering the following situations: eagerly/lazily initialization, thread safety, simplicity, performance issues; in addition, the serialization/deserialization and reflection issues, which we did not mention in this story, can also be evaluated.

If you think there is something wrong with the story or something that needs improvement, please feel free to leave a comment :)

--

--