Understanding the Singleton Pattern in Java: Five Implementations, Tests, and Their Pros & Cons
This article explains the Singleton design pattern, presents five Java implementations (eager, lazy, synchronized, double‑checked locking, static inner‑class, and enum), compares their advantages and disadvantages, and provides multithreaded test code to demonstrate thread‑safety and resource usage.
The Singleton pattern guarantees that a class has only one instance throughout the lifetime of a program, a concept often illustrated by the single "Baron Nashor" in a League of Legends match or the default singleton scope of Spring beans.
Five typical Java implementations are introduced:
Eager initialization – simple and thread‑safe but creates the instance at class loading time, consuming resources even if never used.
Lazy initialization – creates the instance on the first call to getINSTANCE() , but without synchronization it is not thread‑safe.
Synchronized accessor – adds the synchronized keyword to the lazy method, ensuring only one thread can create the instance, at the cost of performance on every call.
Double‑checked locking (DCL) – reduces synchronization overhead by checking the instance twice and declaring it volatile , achieving lazy loading with better performance while remaining thread‑safe.
Static inner‑class holder – leverages JVM class‑loading guarantees; the inner class holds the instance and is only loaded when getINSTANCE() is invoked, providing lazy, thread‑safe initialization without explicit synchronization.
Enum singleton – the most robust solution; an enum with a single element inherently prevents multiple instantiation, and it is immune to reflection and serialization attacks.
Each approach is demonstrated with concise Java code snippets and a multithreaded test that prints the hashCode() of the obtained instance to verify that all threads receive the same object.
Code examples:
public class Singleton01 { // eager
private Singleton01() {}
private static final Singleton01 INSTANCE = new Singleton01();
public static Singleton01 getINSTANCE() { return INSTANCE; }
} public class Singleton02 { // lazy (not thread‑safe)
private Singleton02() {}
private static Singleton02 INSTANCE;
public static Singleton02 getINSTANCE() {
if (INSTANCE == null) { INSTANCE = new Singleton02(); }
return INSTANCE;
}
} public class Singleton03 { // synchronized lazy
private Singleton03() {}
private static Singleton03 INSTANCE;
public static synchronized Singleton03 getINSTANCE() {
if (INSTANCE == null) { INSTANCE = new Singleton03(); }
return INSTANCE;
}
} public class Singleton04 { // double‑checked locking
private Singleton04() {}
private static volatile Singleton04 INSTANCE;
public static Singleton04 getINSTANCE() {
if (INSTANCE == null) {
synchronized (Singleton04.class) {
if (INSTANCE == null) { INSTANCE = new Singleton04(); }
}
}
return INSTANCE;
}
} public class Singleton05 { // static inner‑class
private Singleton05() {}
private static class Holder { private static final Singleton05 INSTANCE = new Singleton05(); }
public static Singleton05 getINSTANCE() { return Holder.INSTANCE; }
} public enum Singleton06 { // enum
INSTANCE;
public static Singleton06 getINSTANCE() { return INSTANCE; }
}Pros and cons are summarized for each method, highlighting simplicity, resource consumption, performance impact, and susceptibility to reflection or serialization attacks.
In conclusion, developers should select the implementation that best fits their requirements; the enum approach is generally recommended for its simplicity and strong guarantees against multiple instantiation.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.