RFR 9: 8138696 : java.lang.ref.Cleaner - an easy to use alternative to finalization
Peter Levart
peter.levart at gmail.com
Thu Oct 15 08:12:36 UTC 2015
On 10/14/2015 07:43 PM, Roger Riggs wrote:
> Hi Alan, Mandy,
>
> I looked at a few of the many uses of finalize and the likely changes.
> The zip Inflater and Deflater are relatively simple cases.
> Some finalizers are not used and can be removed.
> The sun.net.www.MeteredStream example subclasses PhantomCleanable to
> add the state and cleanup
> behavior.
>
> http://cr.openjdk.java.net/~rriggs/webrev-cleaning-finalizers/
>
> Some of the harder cases will take more time to disentangle the
> cleanup code.
> For example, ZipFile, and FileIn/OutputStream (Peter has prototyped
> this).
>
> Roger
Hi Roger,
It's good to see some actual uses of the API and how it is supposed to
be used in migration from finalize() methods. I think empty protected
finalize() method is almost always safe to remove. If the class is not
subclassed, it serves no purpose (unless some other same-package class
or itself is calling it, which can be checked and those calls removed).
If subclass overrides finalize() and calls super.finalize(), its ok (it
will call Object.finalize then when empty finalize() is removed). The
same holds if a subclass calls finalize() as a virtual method regardless
of whether it also overrides it or not.
One thing to watch for is in case a subclass overrides finalize() like this:
class Subclass extends Superclass {
...
@Override protected finalize() {
.... pre-actions ...
super.finalize();
... post-actions...
}
... where the order of cleanup actions has to be orchestrated between
super and subclass. Having a PhantomCleanable replace the finalize() in
a superclass has a similar effect as the following re-ordering in subclass:
@Override protected finalize() {
.... pre-actions ...
... post-actions...
super.finalize();
}
...since finalization is performed before PhantomReference is enqueued.
This re-ordering is luckily often safe as post-actions usually can't use
superclass resources any more and usually don't depend on the state of
superclass. In addition, when superclass actions do happen, they can't
invoke any instance methods if they are refactored to use Cleaner.
This brings up an interesting question. finalize() method allows
subclasses to override it and augment cleanup logic to include any state
changes or resources used by subclass. How about Cleanup API? Subclass
can register it's own Cleanable for own resources, but order of
execution of superclass and subclass Cleanable(s) is arbitrary then.
Cleanables will often be established in constructors and super/subclass
constructors have a defined order of execution. So what about the following:
public class Cleaner {
public Cleanup phantomCleanup(Object referent);
public interface Cleanable {
void clean();
void clear();
}
public interface Cleanup extends Cleanable {
Cleanable append(Runnable action);
Cleanable prepend(Runnable action);
}
public static abstract class PhantomCleanable extends PhantomReference
implements Cleanable { ... }
private static final class PhantomCleanup extends PhantomCleanable
implements Cleanup { ... }
...use...
class SuperClass {
protected final Cleanup cleanup =
XXX.getCleaner().phantomCleanup(this);
SuperClass() {
cleanup.append(() -> {... super class cleanup ...});
}
}
class SubClass extends SuperClass {
SubClass() {
super();
cleanup.prepend(() -> {... pre-actions ...})
.append(() -> {... post-actions ...});
}
}
Regards, Peter
>
>
>
> On 10/14/2015 10:23 AM, Alan Bateman wrote:
>>
>> On 14/10/2015 15:03, Roger Riggs wrote:
>>> Hi Alan,
>>>
>>> So any user of the Cleaner can take advantage of the mechanism, for
>>> example in a different package or module.
>>> For example, Netbeans.
>> Cleaner + Cleanable need to be public of course so maybe we should
>> wait for the examples that extend WeakCleanableRef or cast the
>> Cleanable to a WeakCleanableRef before seeing if this is the right
>> thing or not.
>>
>> -Alan
>
More information about the core-libs-dev
mailing list