How to Implement and Use the Singleton Design Pattern
- August 15, 2017
- Posted by: admin
- Category: Innovation, Java, Uncategorized
The Singleton pattern is one of many design patterns. Its unique characteristic is that it allows the existence of only and only one instance of a class. To ensure the uniqueness of a singleton, it is very important to control the process of its instantiation. Declaring the constructor as private prevents any external script from using the keyword new to directly create an instance of the singleton class. As a result, any code wanting to get an instance of the singleton should pass a specific method named getInstance instead of the usual constructor. This method should be static, and it is the method that can directly execute the instantiation of the singleton using the keyword new:
- Minimal singleton:
The class in Listing 1 seems correct, but it has some imperfections because it immediately loads the instance of the class when the application starts even if the instance is not needed. In some cases, the best approach is to load the instance of the class in memory only when the method getInstance is called. There is an approach called lazy loading that allows a late loading of the instance of a singleton in memory.
- Lazy-loading singleton:
The code in Listing 2 seems correct, but it’s inappropriate in a multithreaded environment and is susceptible to returning more than one instance of the singleton if the method
getInstance()is not protected by a synchronization.
- Singleton class declaration with double-checked locking:
One of the dangers of double-checked locking is that often it will appear to work. This depends on the compiler and how threads are scheduled by the operating system, along with other data-access competition management mechanisms. Reproducing the cause of a crash can be difficult, because crashes are highly unlikely when the code is running in a debugger. The use of double-checked locking must, therefore, be limited as much as possible.
- Synchronized singleton:
Two threads can enter the if block at the same time when INSTANCE is null. The first thread enters the synchronized block to initialize INSTANCE while the second thread is blocked. When the first thread gets out of the synchronized block, the second one, which was blocked, can then enter the synchronized block. But when the second thread enters the synchronized block, it does not verify whether INSTANCE is null before initializing it. In this case, the simplest solution would be to synchronize the get method instance, but this would affect the performance of the program. If the singleton is called frequently in the program, this will make the program work very slowly. So the way to resolve the problem is to have a second verification in the synchronized block. There is an idiom that does this verification: double-checked locking.
- Volatile Singleton:
The volatile reserved word (see Listing 5) provides a solution to this problem by ensuring that different threads correctly handle concurrent access to the single instance of a singleton. However, this access security has a price: accessing a volatile variable is less efficient than accessing a normal variable.