SingletonPattern
Workable solutions
Non-lazy loading
Ideas: Create the singleton instance during the class loading phase.
Cons:
There is no lazy loading and it might resulting in waste of resources.
Lazy loading
Based on synchronized keyword
Idea: Solve the problem with synchronized keyword.
Pros:
Lazy loading
Cons:
Low performance. Only the instance creation part needs to be synchronized.
Double checked locking + Volatile
Why need volatile?
Creating a new object has three steps
Allocate memory for an object
Call the constructor method on the object
Assign the memory address to the object
CPU instruction reordering mght change the order of 2,3.
Thread 1 enters code line B, then it assigns memory address to the object (3 step above). However, it might has not already finished 1 and 2 steps above.
Thread 2 enters code line A, skips line B but end up finding the object empty at line C.
Why need the if condition on Code line O
For performance reasons, without this condition, the code will still works.
However, each time when trying to get the instance variable, it needs to enter the synchronized code block.
With this if condition, the synchronized code block will only be invoked during the creation of the instance.
Why need the if condition on Code line A
If without the block, then code line B could be executed twice by different threads, creating multiple singleton objects.
Static inner class
Winner: Enumeration
This approach is recommended in the "Effective Java" book.
It has the following advantages: https://dzone.com/articles/java-singletons-using-enum
Works with serialization and deserialization.
In order to serialize the above singleton classes, we must implement those classes with a Serializable interface. But doing that is not enough. When deserializing a class, new instances are created. Now it doesn't matter the constructor is private or not. Now there can be more than one instance of the same singleton class inside the JVM, violating the singleton property.
The solution is that we have to implement the readResolve method, which is called when preparing the deserialized object before returning it to the caller.
References:
Works with reflection.
An advanced user can change the private access modifier of the constructor to anything they want at runtime using reflection. If this happens, our only mechanism for non-instantiability breaks.
Last updated