Java Singleton – on demand initialization
On demand initialization is extension of static final implementation. It will prevent eager initialization of the singleton instance, when other fields are accessed. Also known as Bill Pugh‘s solution.
How it works
The SingletonOnDemand will be our Singleton with its only instance hidden inside the SingletonHolder. The class loading mechanism guarantees that on the first access to SingletonOnDemand class all its fields will be initialized, but not fields from the inner static class, because it is another class.
To initialize the singleton instance we have to call getInstance() method that will access the INSTANCE field inside SingletonHolder class, triggering initialization process of the nested static class.
public class SingletonOnDemand { private SingletonOnDemand() {} private static class SingletonHolder { public static final SingletonOnDemand INSTANCE = new SingletonOnDemand(); } public static SingletonOnDemand getInstance() { return SingletonHolder.INSTANCE; } }
Properties of this implementation:
- works in all known versions of Java,
- instantiated only on the first access to getInstance(), hence SingletonHolder.INSTANCE,
- thread-safe without any additional language constructs,
- thanks to the getter can easily be extended to more than one instance,
- easy to implement.
Complete example
In the following example we will access to the FORMAT field, which will initialize SingletonOnDemand class, but won’t initialize it’s singleton instance, because it is hidden in a separate, nested class:
package com.farenda.patterns.singleton; public class SingletonOnDemand { public static final String FORMAT = "Format: '%s'"; private SingletonOnDemand() { System.out.println("Instantiating Singleton..."); } private static class SingletonHolder { // will be initialized only when getInstance() is called public static final SingletonOnDemand INSTANCE = new SingletonOnDemand(); } public static SingletonOnDemand getInstance() { return SingletonHolder.INSTANCE; } }
Let’s see how the above Singleton implementation works:
package com.farenda.patterns.singleton; public class StaticFinalExample { public static void main(String[] args) { System.out.println("Accessing FORMAT field: " + SingletonOnDemand.FORMAT); System.out.println("Now calling SingletonOnDemand.getInstance():"); if (SingletonOnDemand.getInstance() == SingletonOnDemand.getInstance()) { System.out.println("The same instance!"); System.out.printf("%s == %s%n", SingletonOnDemand.getInstance(), SingletonOnDemand.getInstance()); } else { System.out.println("It's not a Singleton!"); } } }
The above code produces the following output:
Accessing FORMAT field: Format: '%s' Now calling SingletonOnDemand.getInstance(): Instantiating Singleton... The same instance! SingletonOnDemand@63947c6b == SingletonOnDemand@63947c6b
When we access the FORMAT field nothing happens, because the field actually holding the Singleton is hidden inside another (nested, but still it’s a different class), that will have its static fields initialized only on the first access to it.
References:
- Java Singleton – static final implementation
- GOF Design Patterns by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (hard read, but with detailed explanation of the pattern)
- Item 3 from Effective Java (2nd Edition) by Josh Bloch (this book is a must read for every good Java developer)