Singleton Design Pattern in Java
This article explains Singleton design pattern in java with UML class diagram. It then takes an example scenario in java and explains it with class diagram and code.
Introduction Singleton Design Pattern is a creational design pattern among the Gang Of Four(GOF) Design PatternsClick to read: Gang Of Four(GOF) Design Patterns. Being a creational design pattern, the Singleton pattern deals with how objects of a class are created - in this case, by making sure that only one object of the class is ever created. What is Singleton Design Pattern The Singleton design pattern ensures that a class has only one instance, and provides a global point of access to that instance. The class itself controls its instantiation: its constructor is private, so no other code can create objects of it, and a static method returns the one instance, creating it if necessary. Every part of the application which asks for the object gets the same instance. Scenarios in which Singleton Design Pattern can be used
Class Diagram for Singleton Design Pattern
Explanation of Singleton Design Pattern's Class Diagram
The example implements an application configuration registry,
Code for the classes shown in Java Example's Class Diagram
OUTPUT on running AppClient.java
Explanation of Java Example's Class Diagram & Code
OUTPUT on running SingletonVariants.java
Summary
In the above tutorial we understood what is Singleton design pattern and the main scenarios in which it is applicable. We then looked at the UML class diagram for Singleton Design Pattern & its explanation, a Java use case implementing the Singleton pattern with the holder idiom, with its class diagram, code and output, followed by an explanation of both the class diagram & code. Lastly, we compared the other common implementations - eager, synchronized, double-checked locking and enum. This concludes the tutorial on Singleton design pattern.
Introduction Singleton Design Pattern is a creational design pattern among the Gang Of Four(GOF) Design PatternsClick to read: Gang Of Four(GOF) Design Patterns. Being a creational design pattern, the Singleton pattern deals with how objects of a class are created - in this case, by making sure that only one object of the class is ever created. What is Singleton Design Pattern The Singleton design pattern ensures that a class has only one instance, and provides a global point of access to that instance. The class itself controls its instantiation: its constructor is private, so no other code can create objects of it, and a static method returns the one instance, creating it if necessary. Every part of the application which asks for the object gets the same instance. Scenarios in which Singleton Design Pattern can be used
- Exactly one instance must exist: When the system needs exactly one object of a class to coordinate actions across the whole application - such as a configuration registry, a cache, a connection pool, or the application's logging service - and having two would cause inconsistent behaviour.
- The instance must be accessible from many places: When many unrelated parts of the application need the same object, and passing it to each of them would be impractical.
- The instance is expensive to create: When creating the object is costly - it loads files, opens connections or builds large data structures - so it should be created once, and ideally only when it is first needed.
Singletonholds its only instance in a private static field,instance.- Its constructor,
Singleton(), isprivate, so no other class can create an object of it withnew. - The public static method
getInstance()is the global access point. It returns the instance, creating it on the first call if it does not exist yet. businessMethod()stands for the class's actual responsibilities, which callers use through the instance.Clientnever creates aSingleton; it always callsSingleton.getInstance()and so always works with the same object.
AppConfig, which loads the application's settings once and makes them available everywhere. It uses the initialization-on-demand holder idiom, which gives a lazily created, thread-safe singleton without any synchronization.
AppConfig.java
//AppConfig.java
import java.util.Map;
public final class AppConfig {
private final Map<String, String> settings;
private AppConfig() {
// Expensive work done only once - e.g. reading a configuration file
System.out.println("Loading configuration...");
settings = Map.of("app.name", "JavaBrahman", "db.url", "jdbc:postgresql://localhost/jb", "cache.size", "500");
}
// The JVM loads Holder - and creates INSTANCE - only when getInstance() is first called
private static class Holder {
static final AppConfig INSTANCE = new AppConfig();
}
public static AppConfig getInstance() {
return Holder.INSTANCE;
}
public String get(String key) {
return settings.get(key);
}
}
AppClient.java (with the main() method)
//AppClient.java
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AppClient {
public static void main(String[] args) throws Exception {
System.out.println("Application started");
AppConfig config = AppConfig.getInstance(); // first call: the instance is created now
System.out.println("App name: " + config.get("app.name"));
AppConfig again = AppConfig.getInstance(); // later calls: the same instance
System.out.println("Same instance: " + (config == again));
// 100 threads asking at the same time still get one instance
Set<AppConfig> seen = ConcurrentHashMap.newKeySet();
try (ExecutorService pool = Executors.newFixedThreadPool(16)) {
for (int i = 0; i < 100; i++) {
pool.submit(() -> seen.add(AppConfig.getInstance()));
}
}
System.out.println("Distinct instances seen by 100 tasks: " + seen.size());
}
}
Application started Loading configuration... App name: JavaBrahman Same instance: true Distinct instances seen by 100 tasks: 1
AppConfigis the singleton. Its constructor is private, and its only instance lives in the static fieldINSTANCEof the nested classHolder.- "Loading configuration..." is printed after "Application started": the JVM initializes a class only when it is first used, so
Holder- and theAppConfigobject - is created on the first call togetInstance(). This is lazy initialization, without any extra code. - Class initialization in the JVM is guaranteed to happen exactly once, even when several threads trigger it at the same time. That is why 100 concurrent tasks all got the same object, without
synchronizedorvolatile. AppClientnever callsnew AppConfig()- which would not compile - and always works with the one shared instance.
Eager, synchronized lazy, double-checked locking and enum singletons
//SingletonVariants.java
public class SingletonVariants {
// 1. Eager: created when the class loads, even if never used. Simple and thread-safe.
static final class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() { }
static EagerSingleton getInstance() { return INSTANCE; }
}
// 2. Lazy with a synchronized method: thread-safe, but every call pays for the lock.
static final class SynchronizedSingleton {
private static SynchronizedSingleton instance;
private SynchronizedSingleton() { }
static synchronized SynchronizedSingleton getInstance() {
if (instance == null) instance = new SynchronizedSingleton();
return instance;
}
}
// 3. Double-checked locking: lazy, and locks only on the first call. 'volatile' is essential.
static final class DclSingleton {
private static volatile DclSingleton instance;
private DclSingleton() { }
static DclSingleton getInstance() {
DclSingleton local = instance;
if (local == null) {
synchronized (DclSingleton.class) {
local = instance;
if (local == null) instance = local = new DclSingleton();
}
}
return local;
}
}
// 4. Enum: the JVM guarantees one instance, even against reflection and serialization.
enum EnumSingleton {
INSTANCE;
String greet() { return "Hello from the enum singleton"; }
}
public static void main(String[] args) throws Exception {
System.out.println("Eager: " + (EagerSingleton.getInstance() == EagerSingleton.getInstance()));
System.out.println("Synchronized: " + (SynchronizedSingleton.getInstance() == SynchronizedSingleton.getInstance()));
System.out.println("Double-checked: " + (DclSingleton.getInstance() == DclSingleton.getInstance()));
System.out.println(EnumSingleton.INSTANCE.greet());
// Reflection can call a private constructor of a class-based singleton...
var ctor = EagerSingleton.class.getDeclaredConstructor();
ctor.setAccessible(true);
System.out.println("Reflection made a second EagerSingleton: " + (ctor.newInstance() != EagerSingleton.getInstance()));
// ...but not of an enum
try {
var enumCtor = EnumSingleton.class.getDeclaredConstructor(String.class, int.class);
enumCtor.setAccessible(true);
enumCtor.newInstance("SECOND", 1);
} catch (IllegalArgumentException e) {
System.out.println("Reflection on the enum: " + e.getMessage());
}
}
}
Eager: true Synchronized: true Double-checked: true Hello from the enum singleton Reflection made a second EagerSingleton: true Reflection on the enum: Cannot reflectively create enum objects
- Eager initialization is the simplest and is thread-safe, but creates the instance even if it is never used.
- A synchronized
getInstance()is lazy and correct, but every call acquires a lock. - Double-checked locking locks only while the instance is being created. The field must be
volatile; without it, another thread could see a partly constructed object. - The enum singleton, recommended in Effective Java, is the most robust: the JVM creates exactly one instance, serialization cannot create a second one, and - as the output shows - reflection cannot call an enum's constructor, while it can create a second instance of the class-based
EagerSingleton.
Gang of Four (GOF) Design Patterns on JavaBrahman
Creational Patterns: Abstract Factory PatternAbstract Factory Design Pattern in Java Builder PatternBuilder Design Pattern in Java Factory Method PatternFactory Method Design Pattern in Java Prototype PatternPrototype Design Pattern in Java Singleton PatternSingleton Design Pattern in Java
Structural Patterns: Adapter PatternAdapter Design Pattern in Java Bridge PatternBridge Design Pattern in Java Composite PatternComposite Design Pattern in Java Decorator PatternDecorator Design Pattern in Java Facade PatternFacade Design Pattern in Java Flyweight PatternFlyweight Design Pattern in Java Proxy PatternProxy Design Pattern in Java
Behavioral Patterns: Chain of Responsibility PatternChain of Responsibility Design Pattern in Java Command PatternCommand Design Pattern in Java Interpreter PatternInterpreter Design Pattern in Java Iterator PatternIterator Design Pattern in Java Mediator PatternMediator Design Pattern in Java Memento PatternMemento Design Pattern in Java Observer PatternObserver Design Pattern in Java State PatternState Design Pattern in Java Strategy PatternStrategy Design Pattern in Java Template Method PatternTemplate Method Design Pattern in Java Visitor PatternVisitor Design Pattern in Java
Analysis of Patterns: Strategy vs State PatternStrategy Design Pattern versus State Design Pattern GOF Patterns OverviewGOF / Gang of Four Design Patterns in Java
Creational Patterns: Abstract Factory PatternAbstract Factory Design Pattern in Java Builder PatternBuilder Design Pattern in Java Factory Method PatternFactory Method Design Pattern in Java Prototype PatternPrototype Design Pattern in Java Singleton PatternSingleton Design Pattern in Java
Structural Patterns: Adapter PatternAdapter Design Pattern in Java Bridge PatternBridge Design Pattern in Java Composite PatternComposite Design Pattern in Java Decorator PatternDecorator Design Pattern in Java Facade PatternFacade Design Pattern in Java Flyweight PatternFlyweight Design Pattern in Java Proxy PatternProxy Design Pattern in Java
Behavioral Patterns: Chain of Responsibility PatternChain of Responsibility Design Pattern in Java Command PatternCommand Design Pattern in Java Interpreter PatternInterpreter Design Pattern in Java Iterator PatternIterator Design Pattern in Java Mediator PatternMediator Design Pattern in Java Memento PatternMemento Design Pattern in Java Observer PatternObserver Design Pattern in Java State PatternState Design Pattern in Java Strategy PatternStrategy Design Pattern in Java Template Method PatternTemplate Method Design Pattern in Java Visitor PatternVisitor Design Pattern in Java
Analysis of Patterns: Strategy vs State PatternStrategy Design Pattern versus State Design Pattern GOF Patterns OverviewGOF / Gang of Four Design Patterns in Java