How to write a Singleton in proper manner?
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.
Introduction
The hardest part of writing a singleton properly is not the syntax. It is deciding whether a singleton is actually the right design at all. Many singleton implementations fail because they ignore thread safety, lifetime control, testing concerns, or accidental global state. If you truly need one shared instance, the proper implementation should be simple, explicit, and safe under concurrency.
What A Singleton Is Supposed To Guarantee
A singleton usually promises two things:
- exactly one instance of a type for a given process or scope
- one shared access path to that instance
That sounds straightforward, but it raises practical questions:
- when is the instance created
- who owns its lifetime
- is it thread-safe
- how will tests replace or isolate it
If those answers are muddy, the singleton will become a source of bugs.
A Good Java Singleton: Initialization-On-Demand Holder
A clean Java implementation uses the holder pattern.
Why this is good:
- lazy initialization
- thread-safe because class initialization is handled safely by the JVM
- no explicit synchronization overhead on normal access
For many Java codebases, this is a much better default than double-checked locking.
Another Strong Java Option: Enum Singleton
If you are in Java and want the most robust built-in singleton semantics, an enum is often the strongest answer.
Usage:
This protects well against serialization and reflection edge cases that can break weaker singleton designs.
Why Many Singleton Implementations Are Bad
A lot of "singleton" code is just a global variable wrapped in a class.
Typical problems:
- not thread-safe
- complicated locking logic
- hidden dependencies across the application
- hard-to-test code because everything reaches into global state
For example, this lazy singleton is not safe in multi-threaded use:
Two threads could observe instance == null at the same time and create two objects.
Ask Whether You Need A Singleton At All
A proper article on singletons should say this clearly: many singletons should really be dependencies managed by dependency injection.
If your app already has a DI container, a process-wide singleton lifetime can often be declared there without hand-writing a singleton pattern at all.
That gives you:
- clearer ownership
- easier tests
- less hidden global state
- simpler replacement in different environments
So the best singleton implementation may be: do not implement the pattern manually.
Use Singletons For The Right Things
Singletons fit best when the object truly represents one process-wide service or resource policy, such as:
- configuration snapshot
- metrics registry
- application-wide cache policy
They are a poor fit for ordinary business services that only became global because it was convenient.
Testing Concerns
A hidden cost of singletons is test contamination. Shared mutable state can leak between tests.
If your singleton stores mutable data, tests become harder to isolate. That is one reason immutable or mostly immutable singleton services are safer than stateful ones.
Common Pitfalls
- Writing a lazy singleton that is not thread-safe.
- Using a singleton as a shortcut for dependency injection.
- Storing mutable global state that leaks across tests and requests.
- Overengineering the implementation with complex locking when the language already offers safer patterns.
- Assuming "only one instance" automatically means "good design."
Summary
- A proper singleton must be thread-safe, explicit, and simple.
- In Java, the holder pattern and enum singleton are both strong options.
- Many manual singleton implementations are really just unsafe global state.
- Prefer dependency injection when the application already has a container.
- Use a singleton only when one shared instance is genuinely part of the design, not just a shortcut.
Related reading
- HttpClientFactory.Create vs new HttpClient
- Implement C Generic Timeout
- Implementing MVC with Windows Forms
- Implementing Singleton with an Enum in Java
- In C, why can''t a Liststring object be stored in a Listobject variable
- In Python, how do I indicate I''m overriding a method?
- Inheriting XML comments from interfaces in C
- Instance attribute attribute_name defined outside __init__

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.