On Wed, 19 Aug 2026 11:55:14 GMT, Per Minborg <[email protected]> wrote:
> This PR proposes to improve the initialization and access performance of
> `LazyConstantImpl`.
>
> ## Tiered access ##
>
> The first-tier (already-initialized) fast path in `get()` remains
> `@ForceInline` and contains only a minimal _acquire_ load of the computed
> constant, a null check, and a cast.
>
> A second-tier method, which includes the successful computation path, is no
> longer annotated with `@DontInline`, allowing the C2 to make its own inlining
> decisions.
>
> In tier three, contention handling and exceptional paths are further isolated
> in a `@DontInline` method and other helper methods.
>
> ## Other optimizations ##
>
> The previous monitor-based initialization with `synchronized` and the
> recursive detection via the native method `Thread.holdsLock()` are replaced
> by a CAS-based _state machine_. A new `state` field can now represent the
> initial supplier, the computing thread, registered waiters, or a terminal
> success/failure state. Normally, the computing `Thread` object is stored
> directly, but in the unusual case a `Thread` also implements `Supplier`, the
> scheme falls back to using a boxed `Long`, keeping the statemachine types
> disjoint.
>
> Contending threads initially spin, followed by short randomized timed
> backoffs. If computation is still in progress, they register in a waiting
> queue and park until signalled by the computing thread. Virtual threads use
> significantly less spinning and timed waiting to limit carrier thread and
> scheduler pressure. Completion atomically detaches and signals registered
> waiters on both successful and failed computations. Interrupted waiters
> retain their interrupt status, and spurious wakeups are handled by rechecking
> the `state`.
>
> The polling loop uses _opaque_ `state` loads while the `state` remains
> unchanged (for optimal performance on weaker platforms) and then performs a
> final _acquire_ load before acting on the state transition. Publication of
> the computed constant continues to use _acquire_/_release_ semantics.
>
> The constructor deliberately initializes the _volatile_ `state` using a
> direct store to avoid bootstrap issues.
>
> ## Tests ##
>
> The PR also proposes to add several new tests and a new benchmark that tests
> dynamic performance when creating and using `LazyConstant` instances on the
> fly.
>
> On multiple platforms, this branch passes testing in:
> - [x] tier1
> - [x] tier2
> - [x] tier3
> - [x] tier4
>
> ## Future work ##
>
> Similar schemes may be introduced in `LazyConstants` under a separate PR.
>
> ---------
> - [x] I confirm that I make this...
Here is a benchmark conducted on a Mac M4:
Base:
Benchmark Mode Cnt Score Error Units
StableValueBenchmark.dynamicStable avgt 10 10.512 ± 0.152 ns/op
Patch:
Benchmark Mode Cnt Score Error Units
StableValueBenchmark.dynamicStable avgt 10 2.177 ± 0.058 ns/op
@Benchmark
public int dynamicStable() {
LazyConstant<Integer> dynamic = LazyConstant.of(supplier);
return dynamic.get() + dynamic.get();
}
The other benchmarks are running with about the same performance.
-------------
PR Comment: https://git.openjdk.org/jdk/pull/32450#issuecomment-5344135426