Singleton design pattern
The singleton pattern is a design pattern that restricts the instantiation of a class to one object.
Sometimes we need to have only one instance of our class for example a single DB connection shared by multiple objects as creating a separate DB connection for every object may be costly. Similarly, there can be a single configuration manager or error manager in an application that handles all problems instead of creating multiple managers.
Sometimes we need to have only one instance of our class for example a single DB connection shared by multiple objects as creating a separate DB connection for every object may be costly. Similarly, there can be a single configuration manager or error manager in an application that handles all problems instead of creating multiple managers.
Examples of Singleton class
- java.lang.Runtime : Java provides a class Runtime in its lang package which is singleton in nature. Every Java application has a single instance of class Runtime that allows the application to interface with the environment in which the application is running. The current runtime can be obtained from the getRuntime() method.
An application cannot instantiate this class so multiple objects can’t be created for this class. Hence Runtime is a singleton class.
Advantage of Singleton design pattern
- Saves memory because object is not created at each request. Only single instance is reused again and again.
Usage of Singleton design pattern
- Singleton pattern is mostly used in multi-threaded and database applications. It is used in logging, caching, thread pools, configuration settings etc.
- Hardware interface access: The use of singleton depends on the requirements. Singleton classes are also used to prevent concurrent access of class. Practically singleton can be used in case external hardware resource usage limitation required e.g. Hardware printers where the print spooler can be made a singleton to avoid multiple concurrent accesses and creating deadlock.
- Logger : Singleton classes are used in log file generations. Log files are created by logger class object. Suppose an application where the logging utility has to produce one log file based on the messages received from the users. If there is multiple client application using this logging utility class they might create multiple instances of this class and it can potentially cause issues during concurrent access to the same logger file. We can use the logger utility class as a singleton and provide a global point of reference, so that each user can use this utility and no 2 users access it at same time.
- Configuration File: This is another potential candidate for Singleton pattern because this has a performance benefit as it prevents multiple users to repeatedly access and read the configuration file or properties file. It creates a single instance of the configuration file which can be accessed by multiple calls concurrently as it will provide static config data loaded into in-memory objects. The application only reads from the configuration file at the first time and there after from second call onward the client applications read the data from in-memory objects.
- Cache: We can use the cache as a singleton object as it can have a global point of reference and for all future calls to the cache object the client application will use the in-memory object.
Significance of Classloader in Singleton Pattern
If singleton class is loaded by two classloaders, two instance of singleton class will be created, one for each classloader.
Lazy loading example
How to prevent Singleton Pattern from Reflection, Serialization and Cloning?
There are mainly 3 concepts which can break singleton property of a class. Let’s discuss them one by one.
- Reflection: Reflection can be caused to destroy singleton property of singleton class, as shown in following example:
Output:- instance1.hashCode():- 366712642 instance2.hashCode():- 1829164700
After running this class, you will see that hashCodes are different that means, 2 objects of same class are created and singleton pattern has been destroyed.Overcome reflection issue: To overcome issue raised by reflection, enums are used because java ensures internally that enum value is instantiated only once. Since java Enums are globally accessible, they can be used for singletons. Its only drawback is that it is not flexible i.e it does not allow lazy initialization.As enums don’t have any constructor so it is not possible for Reflection to utilize it. Enums have their by-default constructor, we can’t invoke them by ourself. JVM handles the creation and invocation of enum constructors internally.As enums don’t give their constructor definition to the program, it is not possible for us to access them by Reflection also. Hence, reflection can’t break singleton property in case of enums. - Serialization:- Serialization can also cause breakage of singleton property of singleton classes. Serialization is used to convert an object of byte stream and save in a file or send over a network. Suppose you serialize an object of a singleton class. Then if you de-serialize that object it will create a new instance and hence break the singleton pattern.
Output:- instance1 hashCode:- 1550089733 instance2 hashCode:- 865113938
As you can see, hashCode of both instances is different, hence there are 2 objects of a singleton class. Thus, the class is no more singleton.Overcome serialization issue:- To overcome this issue, we have to implement method readResolve() method.Output:- instance1 hashCode:- 1550089733 instance2 hashCode:- 1550089733
Above both hashcodes are same hence no other instance is created. - Cloning: Cloning is a concept to create duplicate objects. Using clone we can create copy of object. Suppose, we ceate clone of a singleton object, then it wil create a copy that is there are two instances of a singleton class, hence the class is no more singleton.
Output :- instance1 hashCode:- 366712642 instance2 hashCode:- 1829164700
Two different hashCode means there are 2 different objects of singleton class.Overcome Cloning issue:- To overcome this issue, override clone() method and throw an exception from clone method that is CloneNotSupportedException. Now whenever user will try to create clone of singleton object, it will throw exception and hence our class remains singleton.Output:- Exception in thread "main" java.lang.CloneNotSupportedException at GFG.Singleton.clone(GFG.java:29) at GFG.GFG.main(GFG.java:38)
Now we have stopped user to create clone of singleton class. If you don;t want to throw exception you can also return the same instance from clone method.Output:- instance1 hashCode:- 366712642 instance2 hashCode:- 366712642
Now, as hashcode of both the instances is same that means they represent a single instance.
Comments
Post a Comment