Singleton Pattern – Ensuring a Unique Instance in Java
This article explains the definition, class diagram, and multiple Java implementations of the Singleton pattern—including eager, lazy, double‑checked locking, static inner class, and enum approaches—while discussing thread safety, volatile usage, and practical considerations.
Singleton Pattern – The Unique Object
The Singleton pattern ensures that a class has only one instance and provides a global access point; it is frequently asked in interviews and useful for resources such as thread pools, database connections, caches, and loggers.
Definition of Singleton Pattern
The Singleton pattern guarantees a single instance of a class and offers a globally unique access point.
Class Diagram of Singleton Pattern
(Class diagram image omitted in text version.)
Implementation of Singleton Pattern
Eager Initialization
Static variable is initialized when the class is loaded.
All instances share the same memory region.
The following code demonstrates an eager‑initialized Singleton, which is thread‑safe because the JVM creates the instance during class loading.
public class Singleton {
// Private constructor prevents direct instantiation
private Singleton() {}
// Instance created in static initializer, guaranteeing thread safety
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}Because the JVM loads the class only once, the eager version creates a single instance per ClassLoader; multiple ClassLoaders can lead to multiple instances.
Lazy Initialization
In the lazy approach, the instance is created only when it is first needed, embodying the concept of lazy loading.
Synchronized Method
public class Singleton {
private static Singleton singleton;
private Singleton() {}
// Thread‑safe but low performance due to method‑level synchronization
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}Double‑Checked Locking
public class Singleton {
// volatile ensures correct handling of the instance in multithreaded contexts
private static volatile Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}Double‑checked locking performs two null checks: the first avoids unnecessary synchronization after the instance is created, and the second prevents multiple threads from creating separate instances during the synchronized block.
The volatile keyword prevents instruction reordering, ensuring that other threads never see a partially constructed object.
Instruction Reordering
During object creation, the JVM may reorder the steps of allocating memory, initializing the object, and assigning the reference, which can lead to a thread observing a non‑null but uninitialized instance.
Allocate memory for the singleton.
Invoke the constructor to initialize fields.
Assign the reference to the allocated memory.
If steps 2 and 3 are reordered, another thread could obtain a reference before the constructor finishes, causing errors; volatile prevents this.
Static Inner Class
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}This technique leverages class‑loading semantics: the inner class is not loaded until getInstance() is called, providing lazy initialization with thread safety guaranteed by the JVM.
Enum
enum Singleton {
INSTANCE;
public void method() {}
}Using an enum (introduced in Java 5) ensures a single instance, protects against serialization and reflection attacks, and is recommended by "Effective Java" author Joshua Bloch.
Source Code Analysis of Singleton Pattern in JDK
The class java.lang.Runtime in the JDK is a classic example of an eager‑initialized singleton.
(Image of Runtime source omitted in text version.)
Considerations and Details of Singleton Pattern
The pattern guarantees only one object exists in memory, saving resources and improving performance for frequently created/destroyed objects.
Clients must obtain the instance via the provided accessor method rather than using new .
Typical use cases include heavyweight objects, utility classes, and objects that frequently access databases or files (e.g., data sources, session factories).
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
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.