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...

This patch does two things:
1. remove the call to `Thread.holdsLock(this)`
2. replace `synchronized` with CAS loop

In some benchmarks (1) adds a lot of cost, as `holdsLock` is a native method 
w/o corresponding intrinsic.
While (2) could be beneficial in some settings (I think esp. for lazy 
collections), I'd prefer to see these contributions separated in different PRs 
-- as discussed offline. It might well be that (1) delivers most of the boost 
w/o significant added complexity. We can then later decide if `synchronized` 
needs to go as well.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/32450#issuecomment-5371836084

Reply via email to