On 12/08/2015 07:25 PM, Kim Barrett wrote:
On Dec 8, 2015, at 3:09 AM, David Holmes <david.hol...@oracle.com> wrote:
Question: what happens if an object is registered simultaneously with multiple 
Cleaners? Do we need to warn the user against that?
Aside: I like David's suggested "action" terminology.

Question: what happens if an object is registered simultaneously with
multiple Cleaners? Do we need to warn the user against that?
Registering an object with multiple Cleaners, or even the same Cleaner
multiple times, is not a problem, so long as the various cleanup
actions can cope with that.  This is even expected to occur in
practice.  Consider the conversion of a class hierarchy away from
using finalize() to instead using Cleaners.  A base class may register
a cleanup action for the state associated with that (base) class.  A
derived class may independently register a cleanup action for the
additional state associated with that derived class.  The derived
class's cleanup action might be registered with the same or a
different Cleaner than that used by the base class.


One thing to note is that independent actions registered on the same referent may execute in arbitrary order (each registration is a separate PhantomReference). If order is important then something like the following will be required:


public class BasicClass implements AutoCloseable {

    protected static class BasicState implements Runnable {
        @Override
        public void run() {
            // cleanup actions that access 'BasicState'
        }
    }

    protected BasicState createState() {
        return new BasicState();
    }

    private final BasicState state = createState();

    private final Cleaner.Cleanable cleanable =
        Cleaner.commonCleaner().register(this, state);

    @Override
    public void close() throws Exception {
        cleanable.clean();
    }
}


public class DerivedClass extends BasicClass {

    protected static class DerivedState extends BasicState {
        @Override
        public void run() {
            super.run(); // BasicState cleanup...
            // DerivedState cleanup...
        }
    }

    @Override
    protected BasicState createState() {
        return new DerivedState();
    }
}


...this is not so simple as with finalize() any more, but doable.


It's unfortunate that the "more complicated" PhantomCleanable API did not make it as it would not be much more complicated for such scenarios:


public class BasicClass implements AutoCloseable {

protected static class BasicCleanableState extends CleanerImpl.PhantomCleanable<BasicClass> {

        public BasicCleanableState(BasicClass referent, Cleaner cleaner) {
            super(referent, cleaner);
        }

        @Override
        protected void performCleanup() {
            // cleanup actions that access 'BasicCleanableState'
        }
    }

    protected BasicCleanableState createState(Cleaner cleaner) {
        return new BasicCleanableState(this, cleaner);
    }

private final BasicCleanableState cleanableState = createState(Cleaner.commonCleaner());

    @Override
    public void close() throws Exception {
        cleanableState.clean();
    }
}


public class DerivedClass extends BasicClass {

protected static class DerivedCleanableState extends BasicCleanableState {

public DerivedCleanableState(BasicClass referent, Cleaner cleaner) {
            super(referent, cleaner);
        }

        @Override
        protected void performCleanup() {
            super.performCleanup(); // BasicCleanableState cleanup
            // DerivedCleanableState cleanup
        }
    }

    @Override
    protected BasicCleanableState createState(Cleaner cleaner) {
        return new DerivedCleanableState(this, cleaner);
    }
}


Regards, Peter

Reply via email to