JDK-8327707 : Memory ordering spec updates in java.lang.ref
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.lang
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 23
  • Submitted: 2024-03-09
  • Updated: 2024-05-30
  • Resolved: 2024-05-30
Related Reports
CSR :  
Description
Summary
-------

The `java.lang.ref` package and its classes should specify memory visibility properties.

Problem
-------

Among the optimizations the JVM can make when running code,
it can determine that an object can become unreachable *even if a method on that object is still executing*.

For classes that cleanup using `Cleaner` or finalizer, this phenomenon can lead to unexpected cleanup because `Cleaner` and finalizer perform cleanup on their own threads.

An example  excerpt:

    Resource resource = ...;
    
    protected void finalize() { resource.close(); }
    
    public void doSomething() {
        Resource r = this.resource;
    
        // At this point, 'this' is no longer required.
        // It can be collected, and the finalizer run,
        // closing the resource.
    
        tryToUse(r); // use already-cleaned resource
    }

One can protect against this by using `Reference.reachabilityFence()`:

    public void doSomething() {
        try {
            Resource r = this.resource;
            tryToUse(r);
        } finally {
            Reference.reachabilityFence(this);
        }
    }

(This technique has fixed actual bugs, e.g. [8311902][1] : "Concurrency regression in the PBKDF2 key impl of SunJCE provider".)

Cleanup threads are also subject to Java memory model visibility rules. As such, if a resource is mutated on the main program thread, that mutation may not be seen on the cleanup thread (short of using synchronization actions, volatile variables, etc). This can potentially lead to incorrect cleanup.

However, the GC and relevant portions of the `java.lang.ref` package (`ReferenceQueue`, `Reference.reachabilityFence()`) *already* operate in a way that includes sufficient *happens-before* edges between `Reference.reachabilityFence()` and cleanup threads such that mutations occurring on a thread prior to `reachabilityFence()` will be visible on the cleanup thread.

Thus, the recommended use of try-finally-reachabilityFence() protects against unexpected cleanup AND ensures memory visibility.

Solution
--------

We would like to codify these memory visibility properties in the API spec.
The following will be updated:

* `java.lang.ref` package-info
* `java.lang.ref.Reference`
* `java.lang.ref.ReferenceQueue`
* `java.lang.ref.Cleaner`

Specification
-------------
The specdiff of the proposed API spec changes are attached. For convenience, the specdiff is also available here:

https://cr.openjdk.org/~bchristi/8314480/specdiff.10/overview-summary.html

and a build of the new JavaDoc is here:

https://cr.openjdk.org/~bchristi/8314480/javadoc.10/api/index.html

  [1]: https://bugs.openjdk.org/browse/JDK-8311902
Comments
Moving to Approved.
30-05-2024

The changes in pull/16644 had gone through many changes/iterations over 6 months, I think they are in okay shape now.
22-05-2024