Multiton Pattern
AdvancedExtends Singleton by maintaining a registry of named instances, ensuring one instance per key rather than one instance globally.
Overview
The Multiton (Registry of Singletons) pattern is used when you need exactly one instance per logical key — for example, one database connection per tenant, one logger per class, or one thread pool per task type. Internally it uses a ConcurrentHashMap keyed by the discriminator with computeIfAbsent() for thread-safe lazy initialization. Java's Logger framework uses Multiton: Logger.getLogger("com.example") always returns the same Logger for a given name. The pattern reduces the scope of Singleton from "global" to "global per context".
Thread-Safe Multiton Implementation
Use ConcurrentHashMap.computeIfAbsent() for atomicity. Unlike putIfAbsent() with a pre-created value, computeIfAbsent() only evaluates the factory function when the key is absent, preventing unnecessary instantiation.
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
public class Multiton<K, V> {
private final ConcurrentHashMap<K, V> registry = new ConcurrentHashMap<>();
private final Function<K, V> factory;
public Multiton(Function<K, V> factory) {
this.factory = factory;
}
// Thread-safe: computeIfAbsent is atomic per key
public V getInstance(K key) {
return registry.computeIfAbsent(key, factory);
}
public int registeredCount() { return registry.size(); }
}
// Concrete use case: per-tenant database connection pool
public class TenantConnectionPool {
private static final Multiton<String, HikariDataSource> POOLS =
new Multiton<>(tenantId -> {
HikariConfig cfg = new HikariConfig();
cfg.setJdbcUrl("jdbc:postgresql://db/" + tenantId);
cfg.setMaximumPoolSize(10);
return new HikariDataSource(cfg);
});
public static HikariDataSource forTenant(String tenantId) {
return POOLS.getInstance(tenantId);
}
}
// Usage
HikariDataSource tenantAPool = TenantConnectionPool.forTenant("tenant-a");
HikariDataSource tenantAPool2 = TenantConnectionPool.forTenant("tenant-a");
System.out.println(tenantAPool == tenantAPool2); // true — same instance
HikariDataSource tenantBPool = TenantConnectionPool.forTenant("tenant-b");
System.out.println(tenantAPool == tenantBPool); // false — different instancesEnum-Keyed Multiton
When keys are a fixed finite set (e.g. service tiers), use an enum as the key. EnumMap is faster than HashMap for enum keys and provides compile-time safety.
import java.util.EnumMap;
public enum ServiceTier { FREE, PRO, ENTERPRISE }
public class RateLimiterRegistry {
private static final EnumMap<ServiceTier, RateLimiter> LIMITERS;
static {
LIMITERS = new EnumMap<>(ServiceTier.class);
LIMITERS.put(ServiceTier.FREE, new RateLimiter(10)); // 10 req/s
LIMITERS.put(ServiceTier.PRO, new RateLimiter(100));
LIMITERS.put(ServiceTier.ENTERPRISE, new RateLimiter(1000));
}
public static RateLimiter forTier(ServiceTier tier) {
return LIMITERS.get(tier); // always the same instance per tier
}
}
public class RateLimiter {
private final int requestsPerSecond;
public RateLimiter(int rps) { this.requestsPerSecond = rps; }
public boolean tryAcquire() { /* token bucket logic */ return true; }
}Key Points to Remember
- 1Multiton guarantees one instance per key — expands Singleton scope from global to per-context.
- 2ConcurrentHashMap.computeIfAbsent() is the idiomatic thread-safe implementation.
- 3Java Logging framework (java.util.logging.Logger) is the canonical Multiton example.
- 4Beware of memory leaks — unbounded key sets (e.g. per request-id) cause the registry to grow infinitely.
- 5EnumMap offers O(1) lookups and is more efficient than HashMap for enum keys.
Interview Questions
Sign in to ask AriaWhat is the difference between Singleton and Multiton patterns?
How do you prevent memory leaks in a Multiton with dynamic keys?
Name a Java standard library class that uses the Multiton pattern.
Why use computeIfAbsent() instead of putIfAbsent() in a thread-safe Multiton?
Ask Aria about Multiton Pattern
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.