Is this correct:
SingletonHolder
is only initialised when Singleton.getInstance()
is run. This relies on SingletonHolder
only ever being referenced inside Singleton.getInstance()
. It's thread safe because the class loader takes care of synchronisation.Singleton
, all its static fields are resolved. It's also thread safe because the class loader takes care of synchronisation.Singleton with a holder.
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private Singleton(){ }
}
Singleton without a holder.
public class Singleton{
private static final Singleton INSTANCE = new Singleton();
public static Singleton getInstance(){
return INSTANCE;
}
private Singleton(){ }
}
Update in response to @jan's suggestion that this is a duplicate of What is an efficient way to implement a singleton pattern in Java?. I disagree. I am not asking what is the best way to do it: I am only asking what makes these two specific implementations lazy vs eager loading. Answers like xyz's broadly address lazy vs eager, but not by contrasting the two examples I was trying to examine (or with the same keywords which is why it never came up in my initial searches).
In response to @Sriram, here is my test to prove which is eager vs lazy loading.
public class Singleton {
private static class SingletonHolder {
static {
System.out.println("In SingletonHolder static block.");
}
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
System.out.println("In getInstance().");
return SingletonHolder.INSTANCE;
}
private Singleton() {
System.out.println("In constructor.");
}
private void doSomething() {
System.out.println("Singleton working.");
}
public static void main(String[] args) {
System.out.println("Start of main.");
Singleton.getInstance().doSomething();
System.out.println("End of main.");
}
}
The output shows that the main
method starts before getInstance()
is called, thus lazily loaded.
Start of main.
In getInstance().
In SingletonHolder static block.
In constructor.
Singleton working.
End of main.
public class Singleton {
static {
System.out.println("In Singleton static block.");
}
private static final Singleton INSTANCE = new Singleton();
public static Singleton getInstance() {
System.out.println("In getInstance().");
return INSTANCE;
}
private Singleton() {
System.out.println("In constructor.");
}
private void doSomething() {
System.out.println("Singleton working.");
}
public static void main(String[] args) {
System.out.println("Start of main.");
Singleton.getInstance().doSomething();
System.out.println("End of main.");
}
}
The output shows that the main
method starts after the getInstance()
method is called, thus eagerly loaded.
In Singleton static block.
In constructor.
Start of main.
In getInstance().
Singleton working.
End of main.