Singleton: Thread-Safe Implementations
Build a thread-safe Singleton using double-checked locking, enum, or holder pattern.
Singleton: Thread-Safe Implementations is a free Java Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Singleton Pattern
Singleton ensures that only one instance of a class exists in the JVM. Common use cases: configuration managers, connection pools, logging services.
Naive Singleton — Not Thread-Safe
The classic lazy singleton fails under concurrent access: two threads can both pass the null check simultaneously and create two instances.
public class Config {
private static Config instance;
private Config() {}
public static Config getInstance() {
if (instance == null) { // race condition!
instance = new Config();
}
return instance;
}
}Synchronized Method — Simple but Slow
Adding synchronized to getInstance() makes it thread-safe but locks on every call, even after the instance exists — unnecessary overhead.
public static synchronized Config getInstance() {
if (instance == null) instance = new Config();
return instance;
}Double-Checked Locking
Check without a lock, then check again inside a synchronized block. Requires volatile on the field to prevent instruction reordering.
public class Config {
private static volatile Config instance;
private Config() {}
public static Config getInstance() {
if (instance == null) {
synchronized (Config.class) {
if (instance == null) instance = new Config();
}
}
return instance;
}
}Initialization-on-Demand Holder
The safest and most efficient lazy singleton: a private static nested class holds the instance. The JVM only loads it when getInstance() is first called — class loading is inherently thread-safe.
public class Config {
private Config() {}
private static final class Holder {
static final Config INSTANCE = new Config();
}
public static Config getInstance() {
return Holder.INSTANCE;
}
}Enum Singleton
Effective Java recommends an enum with a single constant. It's concise, thread-safe, serialization-safe, and immune to reflection attacks.
public enum AppConfig {
INSTANCE;
private String apiUrl = "https://api.example.com";
public String getApiUrl() { return apiUrl; }
}
// Usage:
String url = AppConfig.INSTANCE.getApiUrl();Eager Initialization
If startup cost is acceptable, initialize the instance at class load time with a static final field. Simple and thread-safe, but the instance is always created even if never used.
public class Config {
private static final Config INSTANCE = new Config();
private Config() {}
public static Config getInstance() { return INSTANCE; }
}Singleton and Serialization
A serialized-then-deserialized singleton produces a new instance unless you add readResolve() returning INSTANCE. The enum approach handles this automatically.
private Object readResolve() { return INSTANCE; }Singleton and Reflection Attacks
Reflection can invoke private constructors. Defend against it by throwing an exception in the constructor if an instance already exists. Enum singletons are immune by JVM spec.
private Config() {
if (Holder.INSTANCE != null) {
throw new IllegalStateException("Use getInstance()");
}
}Singleton in Dependency Injection Frameworks
In Spring, beans are singletons by default (@Scope("singleton")). You rarely implement the Singleton pattern manually; let the DI container manage it.
@Component // Spring manages a single instance
public class FeatureFlags {
private final boolean darkMode = true;
public boolean isDarkMode() { return darkMode; }
}Testing Singletons
Singletons are hard to unit test because they carry global state. Prefer dependency injection over manual Singleton code; inject mock instances in tests via constructor injection.
Quick Check
Which singleton approach is recommended in Effective Java?
Recap
For thread-safe singletons: use the Initialization-on-Demand Holder or enum approach. Avoid naive lazy initialization. In Spring apps, let the framework handle scope management.
Frequently asked questions
Is the “Singleton: Thread-Safe Implementations” lesson free?
Yes — the full text of “Singleton: Thread-Safe Implementations” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.
What will I learn in “Singleton: Thread-Safe Implementations”?
Build a thread-safe Singleton using double-checked locking, enum, or holder pattern. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Singleton: Thread-Safe Implementations” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Singleton: Thread-Safe Implementations
- Factory Method Pattern
- Abstract Factory for Product Families
- Builder Pattern with Fluent API