The Problem
Sometimes you need exactly one instance of a class across your whole application — a configuration manager, a connection pool, a logger. The Singleton pattern guarantees a class has only one instance and provides a global point of access to it.
Diagram
classDiagram
class Singleton {
-static Singleton instance
-Singleton()
+static getInstance() Singleton
+doSomething()
}
note for Singleton "Private constructor +\nstatic accessor"Java Example (thread-safe, lazy)
public final class ConfigurationManager {
private static volatile ConfigurationManager instance;
private final Map<String, String> settings = new ConcurrentHashMap<>();
private ConfigurationManager() {
settings.put("env", "production");
}
public static ConfigurationManager getInstance() {
if (instance == null) {
synchronized (ConfigurationManager.class) {
if (instance == null) {
instance = new ConfigurationManager();
}
}
}
return instance;
}
public String get(String key) {
return settings.get(key);
}
}The classic double-checked locking is safe in modern Java because of the volatile keyword, but in real projects you rarely need to write this by hand — see the Quarkus example below.
Quarkus Example
In Quarkus (and CDI in general), you almost never hand-roll a Singleton. The container does it for you with @ApplicationScoped:
@ApplicationScoped
public class ConfigurationManager {
private final Map<String, String> settings = new ConcurrentHashMap<>();
@PostConstruct
void init() {
settings.put("env", "production");
}
public String get(String key) {
return settings.get(key);
}
}CDI creates exactly one instance per application and injects it wherever needed:
@Path("/config")
public class ConfigResource {
@Inject
ConfigurationManager configurationManager;
@GET
public String env() {
return configurationManager.get("env");
}
}
Key Takeaways
- Use Singleton when global, shared state truly needs a single owner.
- In plain Java, guard against multithreading issues (
volatile+ double-checked locking, or anenumsingleton). - In Quarkus/CDI, prefer
@ApplicationScopedbeans — the container manages the lifecycle for you, and it’s easier to test (you can mock the bean). - Overuse of Singleton can hide dependencies and hurt testability — inject it, don’t call a static
getInstance()everywhere.

