GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • java.evolved
  • โ†
  • โ†’

This view

  • Original page
  • New address

GeezerVison is showing javaevolved.dev โ€” Stable values | java.evolved

Home / Concurrency / Stable values
Concurrency Advanced

Stable values

  • ๐Ÿ› Report a code issue
  • ๐ŸŒ Report a translation issue
  • ๐Ÿ’ก Suggest a new pattern

Thread-safe lazy initialization without volatile or synchronized.

Concurrency
Code Comparison
โœ• Java 8
private volatile Logger logger;
Logger getLogger() {
    if (logger == null) {
        synchronized (this) {
            if (logger == null)
                logger = createLogger();
        }
    }
    return logger;
}
โœ“ Java 25 (Preview)
private final StableValue<Logger> logger =
    StableValue.of(this::createLogger);

Logger getLogger() {
    return logger.get();
}
Share ๐•
See a problem with this code? Let us know.
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
Since JDK
25
Difficulty
Advanced
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
Stable Values (JEP 502) โ†— StableValue โ†—
Proof
View proof source โ†—
Related patterns
Concurrency Beginner

Virtual threads

Java 8
Thread thread = new Thread(() -> {
    System.out.println("hello");
});
thread.start();
thread.join();
Java 21+
Thread.startVirtualThread(() -> {
    IO.println("hello");
}).join();
Hover to see modern โžœ
JDK 21+ โ†’
Concurrency Advanced

Structured concurrency

Java 8
ExecutorService exec =
    Executors.newFixedThreadPool(2);
Future<User> u = exec.submit(this::fetchUser);
Future<Order> o = exec.submit(this::fetchOrder);
try {
    return combine(u.get(), o.get());
} finally { exec.shutdown(); }
Java 25 (Preview)
try (var scope = new StructuredTaskScope
        .ShutdownOnFailure()) {
    var u = scope.fork(this::fetchUser);
    var o = scope.fork(this::fetchOrder);
    scope.join().throwIfFailed();
    return combine(u.get(), o.get());
}
Hover to see modern โžœ
JDK 25+ โ†’
Concurrency Advanced

Scoped values

Java 8
static final ThreadLocal<User> CURRENT =
    new ThreadLocal<>();
void handle(Request req) {
    CURRENT.set(authenticate(req));
    try { process(); }
    finally { CURRENT.remove(); }
}
Java 25
static final ScopedValue<User> CURRENT =
    ScopedValue.newInstance();
void handle(Request req) {
    ScopedValue.where(CURRENT,
        authenticate(req)
    ).run(this::process);
}
Hover to see modern โžœ
JDK 25+ โ†’
You are visitor 01402503 โ€” GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800ร—600. No cookies required.