Singleton Pattern in Java
Some things should exist only once in a running program: the application's configuration, a connection pool, a cache of exchange rates. If every part of the code created its own, they'd waste memory and disagree with each other. The Singleton pattern makes a class guarantee that only one instance ever exists, and gives everyone a single way to reach it.
The Idea
Every singleton has the same three parts:
- A private constructor, so no one outside can call
new. - A static field holding the one instance.
- A static method (or field) that returns it.
Four Ways to Write One
public class Singletons {
static final class EagerConfig {
private static final EagerConfig INSTANCE = new EagerConfig();
private EagerConfig() { System.out.println("EagerConfig created"); }
static EagerConfig getInstance() { return INSTANCE; }
}
static final class LazyConfig {
private static LazyConfig instance;
private LazyConfig() { System.out.println("LazyConfig created"); }
static LazyConfig getInstance() {
if (instance == null) {
instance = new LazyConfig();
}
return instance;
}
}
static final class HolderConfig {
private HolderConfig() { System.out.println("HolderConfig created"); }
private static class Holder {
static final HolderConfig INSTANCE = new HolderConfig();
}
static HolderConfig getInstance() { return Holder.INSTANCE; }
}
enum AppSettings {
INSTANCE;
private String currency = "INR";
String currency() { return currency; }
}
public static void main(String[] args) {
System.out.println("Program started");
EagerConfig e1 = EagerConfig.getInstance();
System.out.println(e1 == EagerConfig.getInstance());
LazyConfig l1 = LazyConfig.getInstance();
System.out.println(l1 == LazyConfig.getInstance());
HolderConfig h1 = HolderConfig.getInstance();
System.out.println(h1 == HolderConfig.getInstance());
System.out.println(AppSettings.INSTANCE.currency());
}
}Program started
EagerConfig created
true
LazyConfig created
true
HolderConfig created
true
INRHow it works
- Eager: the instance is created when the class loads (here, at the first
getInstance()call). Simple and thread-safe, because class loading is thread-safe. - Lazy: created on the first call. This simple version is not thread-safe: two threads could both see
nulland create two objects. The thread-safe versions (synchronizedand double-checked locking) come with the multithreading lessons, later in the course. - Holder (initialization-on-demand): the nested
Holderclass loads only whengetInstance()first touches it. Lazy and thread-safe, with no locking. - Enum: an enum with one constant. The JVM guarantees exactly one instance, thread-safely, even against reflection and serialization.
Each true confirms that two calls return the same object, and each "created" line prints only once.
Comparing the Approaches
| Approach | Lazy? | Thread-safe? | Safe from reflection and serialization? |
|---|---|---|---|
| Eager static field | No (created at class load) | Yes | No |
Lazy with null check | Yes | No | No |
| Holder idiom | Yes | Yes | No |
| Enum | No (created at class load) | Yes | Yes |
Reflection can call a private constructor and create a second object of a class-based singleton. With an enum, the JVM refuses:
java.lang.IllegalArgumentException: Cannot reflectively create enum objectsCommon Mistakes
The unsynchronized lazy version in multithreaded code. Two instances can be created; use the holder idiom or an enum.
Forgetting the private constructor. Then anyone can call new and there's no singleton.
Using singletons for everything. Most classes need many instances or none; a singleton is the exception.
Interview Corner
How do you create a singleton in Java?
Make the constructor private, keep the single instance in a static field, and return it from a static method. It can be created eagerly in a static final field, lazily inside the accessor, or lazily and thread-safely with a private static holder class. The simplest robust approach is an enum with a single constant, which is thread-safe and can't be duplicated through reflection or serialization.
Why is the enum singleton considered the best?
The JVM guarantees that each enum constant is created exactly once, thread-safely during class initialization. Reflection can't create enum instances, and Java serialization preserves enum identity, so neither can produce a second copy. It also needs the least code.
Practice
- Easy: Write an eager singleton
Counterwith anincrement()method, call it from two places, and show they share the count. - Harder: Rewrite
Counteras an enum singleton, and explain one advantage and one drawback compared with passing aCounterobject into the classes that need it.
Key Takeaways
Was this tutorial helpful?