A @Stable field does not need to be volatile. Avoiding volatile is one of the uses for @Stable.
That said, @Stable is not as foolproof as volatile. It’s more dangerous, and cheaper. You have to do a release store to a stable variable. That’s what the VM does for you automatically for a final, and a stable is like a delayed final. But the VM does not give you the release store automatically; you must do it manually. That’s why @Stable is an internal feature, and StableValue is the “housebroken” version of it. StableValue has to help the VM maintain the appearance of a “final” variable whose initialization got delayed. The wrapAndSet method does this job. This might seem to contradict my previous assertion that StableValue, being mutex based, must not use lock-free idioms. That comment applies specifically to the update operation that takes a lambda. Other operations, such as reading a SV, or hopefully poking a value at a SV can be, and should be, composed of lock-free operations. Why take a lock when it’s just a one-word read or write? On 13 Mar 2025, at 9:07, Maurizio Cimadamore wrote: > On Thu, 13 Mar 2025 15:22:43 GMT, Per Minborg <pminb...@openjdk.org> wrote: > >>> Implement JEP 502. >>> >>> The PR passes tier1-tier3 tests. >> >> Per Minborg has updated the pull request with a new target base due to a >> merge or a rebase. The pull request now contains 246 commits: >> >> - Merge branch 'master' into implement-jep502 >> - Clean up exception messages and fix comments >> - Rename field >> - Rename method and fix comment >> - Rework reenterant logic >> - Use acquire semantics for reading rather than volatile semantics >> - Add missing null check >> - Simplify handling of sentinel, wrap, and unwrap >> - Fix JavaDoc issues >> - Fix members in StableEnumFunction >> - ... and 236 more: https://git.openjdk.org/jdk/compare/4e51a8c9...d6e1573f > > src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java > line 74: > >> 72: @Override >> 73: public boolean trySet(T value) { >> 74: if (wrappedContentAcquire() != null) { > > IMHO, if our goal is to do: > > Object content = this.content; > if (context != null) return content: > synchronized (...) { > if (context != null) return content: > this.context = ... > } > > > Then we might just use a volatile field and synchronized blocks. I don't see > an immediate need for using acquire/release semantics -- > especially when using a monitor. E.g. this should look more like a classic > double checked locking idiom. (but with a stable field to make the first > volatile read more efficient in case the field is already set) > > ------------- > > PR Review Comment: > https://git.openjdk.org/jdk/pull/23972#discussion_r1993850760