Implement Singleton in Java deliberately, with clear lifecycle, thread-safety, and testability boundaries.
Singleton: A pattern that guarantees one accessible instance of a type within a process and gives controlled global access to it.
The key word is controlled. In Java, a Singleton is not automatically good design just because the implementation is technically correct. The real question is whether the system truly benefits from one shared instance or whether the pattern is being used as disguised global state.
A basic eager singleton is simple:
1public final class AppConfig {
2 private static final AppConfig INSTANCE = new AppConfig();
3
4 private AppConfig() {}
5
6 public static AppConfig getInstance() {
7 return INSTANCE;
8 }
9}
This works because construction happens once during class initialization. There is no lazy logic and no race condition around creation.
A leaf page about implementing Singleton should still show the main choices clearly:
| Variant | Good fit | Main caveat |
|---|---|---|
| Eager static field | Cheap startup-owned instance | Pays construction cost whether used or not |
| Synchronized accessor | Simple code with infrequent access | Locks on every access path |
| Initialization-on-demand holder | Lazy creation with good clarity | Slightly less obvious to readers unfamiliar with the idiom |
| Double-checked locking | Rare cases needing lazy init with explicit control | Higher complexity and easier to get wrong |
| Enum singleton | Serialization-safe, process-wide singleton with minimal ceremony | Awkward when lazy parameters or subclass-like variation matter |
For deeper detail, see:
When Java teams truly need lazy initialization and want to avoid unnecessary synchronization overhead, the holder idiom is usually a strong option:
1public final class MetricsRegistry {
2 private MetricsRegistry() {}
3
4 private static final class Holder {
5 private static final MetricsRegistry INSTANCE = new MetricsRegistry();
6 }
7
8 public static MetricsRegistry getInstance() {
9 return Holder.INSTANCE;
10 }
11}
This relies on class initialization guarantees instead of manual locking logic.
Before choosing Singleton, ask:
Those questions matter more than the mechanics of private constructors.
Singleton can be reasonable for:
Even then, the state inside the singleton should be reviewed carefully. A singleton full of mutable runtime state is often where hidden coupling begins.
The implementation choice is only part of the story. Java singleton code also needs to survive surrounding language features.
Common hazards:
This is why singleton implementation pages should not stop at “private constructor plus static accessor.” For a focused treatment of those edges, see Serialization Issues with Singleton.
The pattern becomes harmful when:
The most common Java singleton bug is not thread safety anymore. It is architectural laziness.
If a singleton is justified, keep its public surface small and its responsibilities narrow. It should not become a service locator, configuration bag, or miscellaneous object registry.
When reviewing a Java singleton, ask:
Singleton is valid when singularity is part of the model. It is a smell when singularity is only a convenience story.