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
