Singleton pattern
Singleton pattern
The singleton pattern is probably the most widely used design pattern since the inception of Java. It is a simple pattern, easy to understand and to use. Sometimes it is used in excess, and in scenarios where it is not required. In such cases, the disadvantages of using it outweigh the advantages it brings. For this reason, the singleton is sometimes considered an anti-pattern. However, there are many scenarios where singletons are necessary.
As its name suggests, the singleton pattern is used to ensure that only a single instance of an object can be created. In addition to that, it also provides global access to that instance. The implementation of a singleton pattern is described in the following class diagram:

The implementation of the singleton pattern is very simple and consists of a single class. To ensure that the singleton instance is unique, all singleton constructors should be made private. Global access is done through a static method that can be globally accessed to get the singleton instance, as shown in the following code:
Synchronized singletons
The code for synchronized singletons is simple and efficient, but there is a situation we should take into consideration. If we use our code in a multithreading application, it may be the case that two threads invoke the getInstance method at the same time when the instance is null. When this happens, it may be the case that the first thread proceeds to instantiate the singleton using the new operator, and, before finishing it, the second thread checks whether the singleton is null. Since the first thread didn't finish instantiating it, the second thread will find that the instance is null, so it will start instantiating it too.
This scenario may seem almost impossible, but if it takes a long time to instantiate the singleton, the likelihood of it happening is high enough that it cannot be neglected.
The solution to this problem is very simple. We have to make the block that checks whether the instance is null thread-safe. This can be done in the following two ways:
- Making the getInstance method thread-safe by adding the synchronized keyword to its declaration:
- Wrapping the if (instance == null) condition in a synchronized block. When we use the synchronizedblock in this context, we need to specify an object that provides the lock. We use the Singleton.class object for this, as shown in the following code snippet:
Synchronized singleton with double-checked locking mechanism
The previous implementation is thread-safe but it introduces an unnecessary delay: the block that checks whether the instance has already been created is synchronized. This means that the block can be executed by only one thread at a time, but locking makes sense only when the instance has not been created. When the singleton instance has already been created, each thread can get the current instance in an unsynchronized manner.
Adding an additional condition before the synchronized block will move the thread-safe locking only when the singleton has not been instantiated yet:
Lock-free thread-safe singleton
One of the best implementations of the singleton pattern in Java relies on the fact that a class is loaded a single time. By instantiating the static member directly when declared, we make sure that we have a single instance of the class. This implementation avoids locking mechanisms and additional checking to see whether the instance has already been created:
Lock-free thread-safe singleton
One of the best implementations of the singleton pattern in Java relies on the fact that a class is loaded a single time. By instantiating the static member directly when declared, we make sure that we have a single instance of the class. This implementation avoids locking mechanisms and additional checking to see whether the instance has already been created:
Early and lazy loading
Singletons can be split into two categories, depending on when the instance object is created. If the singleton is created when the application is started, it is considered an early/eager instantiation. Otherwise, if the singleton constructor is invoked when the getInstance method is invoked for the first time, it is considered a lazy-loading singleton.
The lock-free thread-safe singleton presented in the previous example is considered an early-loading singleton in the first version of Java. However, in the latest version of Java, classes are loaded when they are needed, so that version is also a lazy-loading version. Furthermore, the moment that a class is loaded depends on the JVM implementation and may differ from one version to another. Making design decisions based on JVM implementation should be avoided.
Currently, there is no reliable option in Java for creating an early loading singleton. If we really need an early instantiation, we should enforce it at the start of the application, by simply invoking the getInstance() method, as shown in the following code:
Comments
Post a Comment