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

Reply via email to