Singleton Class in Java

This is one of the most popular topic often asked in the interviews. As the name itself explains everything, Singleton means ONLY ONE. A class that returns only one instance, shared by the whole application is known as a Singleton Class.

Singleton’s prime purpose is to control object creation, limiting the number of objects out of a class in a java application, to only one.

You might now be wondering how can we achieve that?

Of course Java provides us a provision for that. And yes, you are guessing it right, we can achieve this singleton behavior using the static keyword.

We have already explored a lot about static keyword in our previous article, and its recommended that you have the basic understanding of static keyword before going ahead.

Coming again, how can we create a Singleton class?

There are two ways to create a Singleton class:

  • Lazy initialization
  • Eager Initialization

To demonstrate the singleton behavior with the lazy initialization approach, let’s start with creating a class

Now let’s now create another class with the eager initialization approach.

Our class with the main method would look like:

Note that the SingletonClass can be substituted with LazySingletonClass or EagerSingletonClass in the above snippet.

When we run the above main method, below is what we get the output on the console:

After going through the above code you might be having some very obvious questions that, why have we added double null checks with the Synchronized block in LazySingletonClass and what is the use of volatile keyword? Definitely we have an answer to that and it’s for thread safety. Let’s explore a little more on this.

The volatile keyword helps in concurrency control in a multi-threaded environment. What would have happened otherwise? If the singleton object gets created and just exactly after it’s creation, loses the CPU, other threads wont be able to know that the singleton class has already been instantiated, which in that case, should not allow another object of the same singleton class to be created. The volatile keyword thereby makes sure that this erratic scenario never happens. Even if the application loses the CPU, the singleton instance still gets updated in the main memory and all other reader threads are now aware that the singleton object has already been created.

But the question still remains, why the two null checks?

Let’s consider if there was no synchronization block, the code would then have been:

Suppose that a thread 1 is preempted by another higher priority thread 2 at line 3 just before the assignment is made, the instance member variable will still be null. This thread 2 now enters the if block since the condition instance==null still holds true. Once thread 2 is done, thread 1 comes to the action again and continues back from where it left, which means that it is able to create yet another instance of the singleton class, since it had already entered into the if block previously. In that case, two distinct singleton instances gets created, which is unacceptable. So to avoid this condition we need to apply double null checking with a synchronized block, such as –

Now this means that even if the thread 2 preempts thread 1 at line 3, it enters and completes with the execution of synchronized block. Next time when thread 1 comes back to action, now enters the synchronized block, faces another null check, which now stops it from creating a new singleton instance, since at this point instance is no more null as thread 2 already did the job.

The synchronized block in the above snippet makes sure that no two threads enter it at the same time.

Let’s now try to justify the use of volatile keyword here.

Until the thread 2 comes out of synchronized block, the value of instance will not be synchronized and updated in the main memory. So other reader threads trying to access the instance variable while thread 2 is in the middle of synchronized block execution, such as just after the creation of the Singleton object at line number 5, might possibly NOT see its updated value. Initializing the instance member variable as volatile makes sure that the main memory updates itself as soon as the Singleton object gets created at line number 5. Any subsequent access to the instance variable by the reader threads, now fetches a not null value even though thread 2 has not yet exited the synchronized block.

Also, to avoid cloning of the singleton objects, we need to override the clone() method of Object class and throw CloneNotSupportedException exception, so nobody can clone the singleton object, as we have already done for both of the singleton classes towards the start of this article.

Receive our updates to your inbox

Get more stuff like this
in your inbox

Subscribe to our mailing list and get interesting stuff and updates to your email inbox.