When Singleton should be used?
Singleton should be used incase creation of Object is costly or heavy I.E. DBConnection. It should not be used if the Object is mutable.
- Eager initialization
- Lazy initialization
- Static block initialization
- Using Synchronized method
- Using Synchronized block
- Double Checked Locking
- Enum Singleton
- Initialization on demand holder idiom
3 Things are common across all singleton implementation
private constructor
public static getInstance Method
private static instance field
Eager initialization
An instance of Singleton Class is created at the time of class loading
EagerInitialized.java
package com.mugil.singleton; public class EagerInitialized { private static final EagerInitialized instance = new EagerInitialized(); //Private Constructor private EagerInitialized() { } public static EagerInitialized getInstance() { return instance; } }
Lazy Initialization
With lazy initialization you crate instance only when its needed and not when the class is loaded
LazyInitialized.java
package com.mugil.singleton; public class LazyInitialized { public static LazyInitialized instance = null; private LazyInitialized() { } public static LazyInitialized getInstance(){ if(instance == null){ instance = new LazyInitialized(); } return instance; } }
Static Block Initialization
Static block initialization is similar to eager initialization, except that an instance of class is created in the static block that provides an option for exception handling.
StaticBlockInitialized.java
package com.mugil.singleton; public class StaticBlockInitialized { private static StaticBlockInitialized instance; private StaticBlockInitialized() { } // Static block initialization for exception handling static { try { instance = new StaticBlockInitialized(); } catch (Exception e) { throw new RuntimeException("Exception occurred in creating singleton instance"); } } public static StaticBlockInitialized getInstance() { return instance; } }
Using Synchronized Method
The easier way to create a thread-safe singleton class is to make the access method synchronized, so that only one thread can execute this method at a time.
ThreadSafeSing.java
package com.mugil.singleton; public class ThreadSafeSing { private static ThreadSafeSinginstance; private ThreadSafeSing(){} public static synchronized ThreadSafeSing getInstance(){ if(instance == null){ instance = new ThreadSafeSing(); } return instance; } }
Using Synchronized Block
The easier way to create a thread-safe singleton class is to make the access method synchronized, so that only one thread can execute this method at a time. Refer the link for the same Link
ThreadSafeSing.java
package com.mugil.singleton; public class ThreadSafeSing { private static ThreadSafeSinginstance; private ThreadSafeSing(){} public static ThreadSafeSing getInstance(){ Synchronized(ThreadSafeSing.class){ if(instance == null){ instance = new ThreadSafeSing(); } } return instance; } }
Double Checked Locking Singleton
Above Implementation of Singleton provides thread safety buy has a hit over performance. The performance hit happens when two threads try to get the instance of object in getInstance() method but only one is allowed within Synchronized block while the other needs to wait until the first is done checking irrespective of the instance is already created or not.
In the Below method of Implementing Singleton, we again use Synchronized Block but we do the check for the availability of the object instance even before taking lock.
DCCSingleton.java
package com.mugil.singleton; public class DCCSingleton{ private static DCCSingletoninstance; private DCCSingleton(){} public static DCCSingleton getInstanceUsingDoubleLocking() { if(instance == null){ synchronized (DCCSingleton.class) { if(instance == null){ instance = new DCCSingleton(); } } } return instance; } }
Refer the Link for how Double Checked Locking works
ENUM Singleton
enum fields are compile time constants, but they are instances of their enum type. And, they’re constructed when the enum type is referenced for the first time.
ENUMSingleton.java
Simple Singleton using enum for DBConnection
public enum EnumSingleton { INSTANCE; // instance vars, constructor private final Connection connection; private Singleton() { //Initialize the connection connection = DB.getConnection(); } public Connection getConnection(){ return connection; } // Static getter public static Singleton getInstance() { return INSTANCE; } }
The way it works we can either use getInstance() method or directly call EnumSingleton.INSTANCE to access connection Object.
The Connection can be created using the Below Code
Connection Conn = Singleton.getInstance().getConnection();
Minimal Implementation using ENUM
public enum MySingleton { INSTANCE; }
In the above code we may get a doubt how the object is created as we have a empty private constructor which is never invoked?.
The above code gets converted as one below. Above code has an implicit empty constructor. Lets make it explicit instead,
public enum MySingleton { INSTANCE; private MySingleton() { System.out.println("Here"); } }
Now when we make a call as below the private constructor is invoked and object gets created
public static void main(String[] args) { System.out.println(MySingleton.INSTANCE); }
Output
Here INSTANCE
Initialization on demand holder idiom
How it works?
- The Below implementation is a lazy loading and thread safe method of creating Singleton
- On calling the getInstance() method the lazySingletonClass would be initialized which in turn makes the INSTANCE to be initialized.
- Class initialization is inherently thread-safe and if you can have an object initialized on class initialization the object creation too are thread-safe.
- Singleton instance variable will never be created and or initialized until getInstance() is invoked. And again since class initialization is thread-safe the instance variable of IntiailizationOnDemandClassholder will be loaded safely, once and is visible to all threads.
public class Singleton { private Singleton(){} public static class lazySingletonClass{ private static final Singleton INSTANCE = new Singleton(); } public Singleton getInstance(){ return lazySingletonClass.INSTANCE; } }
When Object is Created | Thread Safe | Performance | Comments | |
---|---|---|---|---|
Eager Initialization | Object Gets Created once the Class is Loaded | Yes | Bad | Object is created everytime when the class is accessed |
Lazy Initialization | Object is Created once required | No | In lazy initialization you give a public API to get the instance. In multi-threaded environment it poses challenges to avoid unnecessary object creation | |
Static Block Initialization | Object is Created once Static Block is loaded | Yes | Bad | Not a good idea to load resources from static block as it causes performance hit during app startup |
Synchronized Method | Object is Created once getInstance is called | Yes | Bad | Thread safety is guaranteed.Slow performance because of whole method locking is done |
Synchronized Block | Object is Created once getInstance is called | No | Two singleton instances may be created when context switching happens after checking instance is null | |
Double Checked Locking | Object is Created once getInstance is called | Yes | Good | Instance check is done twice |
Enum Implementation | Object Created using enum is referenced | Yes | Good | |
Initialization on demand holder idiom | Object Created when static class is initiazlied by calling getInstance method | Yes | Good | Class initialization is inherently thread-safe and if you can have an object initialized on class initialization the object creation too are thread-safe |
Note
Dont be confused between Class Loading and Initialization. In the Initialization on demand holder method of singleton you can easily get confused as the static inner class wont be loaded when the outer class loads. The implementation relies on the fact that during initialization phase of execution within the Java Virtual Machine (JVM) as specified by the Java Language Specification (JLS) When the class Singleton is loaded by the JVM, the class goes through initialization. Since the class does not have any static variables to initialize, the initialization completes trivially. The static class definition lazySingletonClasswithin it is not initialized until the JVM determines that lazySingletonClassmust be executed. The static class lazySingletonClassis only executed when the static method getInstance is invoked on the class
The static class lazySingletonClass is only executed when the static method getInstance is invoked on the class Singleton , and the first time this happens the JVM will load and initialize the lazySingletonClass class. The initialization of the lazySingletonClassclass results in static variable INSTANCE being initialized by executing the (private) constructor for the outer class Something. Since the class initialization phase is guaranteed by the JLS to be sequential, i.e., non-concurrent, no further synchronization is required in the static getInstance method during loading and initialization