The current specification of @Stable is here in the javadoc:
Key idea: If the JIT gets to a stable variable at compile time, and that stable variable does not have a default value (null/zero/false), then it can use that value as a constant.
With stable values you can build lazily elaborated but constant-folded structures, such as caches. They can include cycles.
There are two ways to make this happen, and I don't know which is better.
A. Dynamically enforce a single-update restriction on an affected variable. Guarantee that interfering writes are dealt with before they can break the observed stability of the variable. (A1. throw an exception, A2. drop the update on the floor, A3. allow the update but only if the value is somehow "equivalent" to the old value, A4. allow the update and deoptimize like crazy.)
B. Do not enforce anything, but allow the JMM to reach back in time to retrieve the first-set value. I.e., if a stable variable is set more than once, the JMM would allow either of the values (or the first and last?) to be produced. Then the user is on his own if the stability assurance is a lie, but the compiler is given enough room to do optimizations, and they work for well-behaved programs.
We seem to need stable array elements as well as stable fields. But arrays are "vanilla", and don't know whether they are supposed to be stable. Given a random array, how do we know its components are supposed to be stable? The plan A version of stable arrays looks a lot like frozen arrays (as stable fields are to final fields).
The special pleading for safe publication via a final variable should probably be extended to stable variables.
Is it allowed to store a null/zero/false value to a stable variable? Probably not. This could be checked (at least in plan A).
Stability travels well with racy updates. A stable variable acts as a cache which is filled when a non-null payload value. Given the simplicity of the state transition, it is reasonable to update the variable in a racy way, where several threads may concurrently compute the cached value and concurrently attempt to store it. This feels like a sort of "final volatile" variable.
Two racers may store distinct but equivalent values into a stable variable, such as two distinct evaluations of new Integer(42). Can this be made innocuous? It can under Plan B. Allowing distinct equivalent values allows you to get away from interning the payloads. (Yet again, a-cmp is a liability.) Alternatively, every stable variable assignment can be treated as a CAS from null to the new value. (See plan A.)