Hi Kim,

Thanks for the comments:

I updated the webrev[2] and javadoc[1] with the editorial improvements.

On 12/02/2015 06:20 PM, Kim Barrett wrote:
On Dec 2, 2015, at 3:23 PM, Roger Riggs <roger.ri...@oracle.com> wrote:
Please review the java.lang.ref.Cleaner and tests following the recommendation 
to simplify the public
interface to support only phantom cleanup.

Webrev:
  http://cr.openjdk.java.net/~rriggs/webrev-cleaner-8138696/

Javadoc:
   http://cr.openjdk.java.net/~rriggs/cleaner-doc/index.html
------------------------------------------------------------------------------
src/java.base/share/classes/java/lang/ref/Cleaner.java
  109      * The Cleaner terminates when it is unreachable and all of the 
objects
  110      * registered are unreachable and corresponding cleaning functions 
are complete.
and
  131      * The Cleaner terminates when it is unreachable and all of the 
objects
  132      * registered are unreachable and corresponding Runnables are 
complete.

Cleaner termination does not require registered objects to be
unreachable, only that the registered cleaning functions are
complete.  A completed call to clean() on an associated Cleanable also
counts as a cleaning function completion, irrespective of whether the
associated object is unreachable.

Yes, the cleaning functions can be completed by calling clean.

* The Cleaner terminates when it is unreachable and all of the
* registered cleaning functions are complete.


Also, there is the inconsistent terminology between "cleaning
functions" and "Runnables".
Updated to use cleaning function as a generic; Runnable is retained
as the type of the function.

------------------------------------------------------------------------------
src/java.base/share/classes/java/lang/ref/Cleaner.java
  134      * Typically, only a single thread is requested from the 
ThreadFactory.

Is that an actual promise?  If not, it might be better to not say
anything at all.
An @implNote clause it provides information about the implementation.
'Typically' reduces the statement to informative.
So no, not a promise.

------------------------------------------------------------------------------
src/java.base/share/classes/java/lang/ref/Cleaner.java
  140     public static Cleaner create(ThreadFactory threadFactory) {
  141         Objects.requireNonNull(threadFactory, "threadFactory");

Is there a reason to require threadFactory to be non-null?  This means
that if a caller obtains a factory by some means that might return
null, the caller needs to conditionally select which create call to
make.
Stylistically, nulls are not usually used as defaults and may obscure
unintentional cases of the caller (a bug).

------------------------------------------------------------------------------
src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java
  117      * Process queued Cleanables as long as the cleanableList is not 
empty.

There are multiple lists of cleanables; all must be empty.
fixed

Similarly for "the list" here:

  118      * A Cleanable is in the list for each Object and for the Cleaner
  119      * itself.
fixed

------------------------------------------------------------------------------
src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java
  199         PhantomCleanable(CleanerImpl cleanerImpl) {
  200             super(null, null);

This feels mildly icky, passing a null referent to a Reference
constructor.  (Similarly for the other XxxCleanable classes.)

Also, in this case, passing a null queue to the PhantomReference
class.

Both (presently) work, but still...
A dummy object could be allocated for the referent but it would have not purpose.
(and null is allowed).

------------------------------------------------------------------------------
src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java
  223         private boolean remove() {
  224             PhantomCleanable<?> list = cleanerImpl.phantomCleanableList;
  225             synchronized (list) {
  226                 if (next != this) {

Shouldn't that be "if (prev != this) {" ?

Insertion is always after the special sentinal, so "prev" should
always be non-"this" when in the list, and "this" when out.  But
"this" could be the last element in the list, in which case
"next == this", even though in the list.
Each list is a doubly linked circular list with the list head as a separate distinct ref and is never removed. When not in a list prev == next == this; (except in list root; the list is empty)
When it is in a list, prev != this && next != this


[Applies to all three of {Soft,Weak,Phantom}Cleanable.]

------------------------------------------------------------------------------
src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java
  237         /**
  238          * Returns true if the list's next reference refers to itself.
  239          *
  240          * @return true if the list is empty
  241          */
  242         boolean isListEmpty() {
  243             PhantomCleanable<?> list = cleanerImpl.phantomCleanableList;
  244             synchronized (list) {
  245                 return next == list;
  246             }
  247         }

Based on the description, one might expect some occurrence of "this"
in the body.  This function must only be applied to the special head
sentinal, so a pre-condition is "list == this".  Either an assert or
some mention of this would make this easier to understand.

[Applies to all three of {Soft,Weak,Phantom}Cleanable.]
The implicit reference to 'this' is in via cleanerImpl.

All of the functions insert, remove, isListEmpty need to lock on the list root and explicitly referring to the list root (via the clearerImpl) in each method
keeps them aligned.
IsListEmpty could be recoded to operate only on the distinguished root entry
but it would be harder to see that the same lock is being used consistently.

Thanks, Roger

[1] http://cr.openjdk.java.net/~rriggs/cleaner-doc/
[2] http://cr.openjdk.java.net/~rriggs/webrev-cleaner-8138696/


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


Reply via email to