// Eager Loadingclass LoggerSingleton { // notice static private static LoggerSingleton instance = new LoggerSingleton(); // notice private constructor private LoggerSingleton() {} // notice static // instance can be accessed only here public static LoggerSingleton getInstance() { return instance; } }
Lazy Loading: Not Thread Safe
class LoggerSingleton { private static LoggerSingleton instance = null; private LoggerSingleton() {} public static LoggerSingleton getInstance() { if (instance == null) { instance = new LoggerInstance(); } return instance; } }
Synchronized method: Thread Safe
Never used since locking method is expensive
Once the instance is created, if a lot of threads call getInstance(), then it is useless to keep the other threads waiting
Need to use volatile to prevent visibility problem. See volatile
class LoggerSingleton { private static volatile LoggerSingleton instance = null; private LoggerSingleton() { } synchronized public static LoggerSingleton getInstance() { if (instance == null) { instance = new LoggerInstance(); } return instance; } }
Single Checked Locking: Not Thread Safe
Block synchronized locking is less expensive than method level locking since we only need to synchronize less code
Notice that block level locking is not actually executed much, instead the first check itself returns instance if available
LoggerSingleton.class is an immutable object of Class<?> which is considered for monitor object
In rare scenario, Both threads can enter synchronized block one by one
This will lead to two instances being created
class LoggerSingleton { private static volatile LoggerSingleton instance = null; private LoggerSingleton() { } public static LoggerSingleton getInstance() { if (instance == null) { // Bad: both t1 and t2 come here // and enter one by one inside the following block synchronized(LoggerSingleton.class) { instance = new LoggerInstance(); } } return instance; }}
Double Checked (Single) Locking: Thread Safe
This is used in production but it also has some flaws. what flaws??
class LoggerSingleton { private static volatile LoggerSingleton instance = null; private LoggerSingleton() { if (instance != null) { throw RuntimeException("Don't try to be smart"); } } public static LoggerSingleton getInstance() { if (instance == null) { synchronized(LoggerSingleton.class) { if (instance == null) { instance = new LoggerInstance(); } } } return instance; }}
Method 1: Using private static holder class (Thread Safe)
JVM will call static initializer only when class is accessed
public class Singleton { private Singleton() { } // static class private static class SingletonHolder { // static initilizer will be called only once by JVM public static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; }}
prevent by throwing exception in constructor if instance already exists
There is still flaw, what will happen if somebody uses reflection directly and create Singleton without invoking Singleton.getInstance() ??
class Singleton { private static volatile instance; private Singleton() { // To make sure if somebody do not call constructor // using reflection if (instance != null) { // important to throw `RuntimeException` // since it is unchecked exception // otherwise you need to handle it in other places throw RuntimeException("Don't try to be smart"); } }}
By Performing locking from outside
Class objects can be locked from outside using synchronized