◐ Shell
clean mode source ↗

Stable values

Code Comparison

private volatile Logger logger;
Logger getLogger() {
    if (logger == null) {
        synchronized (this) {
            if (logger == null)
                logger = createLogger();
        }
    }
    return logger;
}
private final StableValue<Logger> logger =
    StableValue.of(this::createLogger);

Logger getLogger() {
    return logger.get();
}

Why the modern way wins

🧹

Zero boilerplate

No volatile, synchronized, or null checks.

JVM-optimized

The JVM can fold the value after initialization.

🛡️

Guaranteed once

The supplier runs exactly once, even under contention.

Old Approach

Double-Checked Locking

Modern Approach

StableValue

JDK Support

Stable values

Preview

Preview in JDK 25 (JEP 502). Requires --enable-preview.

How it works

StableValue provides a lazily initialized, immutable value with built-in thread safety. No double-checked locking, no volatile fields, no synchronized blocks. The JVM can even optimize the read path after initialization.

Related Documentation

Proof