RFR 9: 8138696 : java.lang.ref.Cleaner - an easy to use alternative to finalization

Roger Riggs Roger.Riggs at oracle.com
Tue Dec 8 20:01:17 UTC 2015


Hi Peter,

Tricky indeed,  the visibility of what is captured is too subtle.
Even if the field is final, it captures this, not the value.
I suppose it is more efficient not to copy field values.

But other than recommending capturing only local variables and arguments,
is there any other relevant advice?

I added examples of both nested class based and lambda based cleaners to the
Cleaner javadoc in the @apiNote.


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

Thanks, Roger


On 12/08/2015 01:51 PM, Peter Levart wrote:
>
>
> On 12/08/2015 04:34 PM, Roger Riggs wrote:
>> Hi Peter,
>>
>> Thanks for the example and explanations.
>>
>> For simple cleanup of specific state values, I probably would have 
>> used lambda instead of an explicit
>> inner class but both styles use the same mechanism.
>> The point about using a shared cleaner can be reinforced in the 
>> example too.
>>
>> public static class CleanerExample implements AutoCloseable {
>>
>>         FileDescriptor fd = ...;
>>
>>         private static final Cleaner cleaner = Cleaner.create();
>>
>>         private final Cleaner.Cleanable cleanable = 
>> cleaner.register(this, () -> fd.close());
>>
>>         @Override
>>         public void close() {
>>             cleanable.clean();
>>         }
>>     }
>>
>
> Sorry Roger, but this example is flawed. This is tricky! The lambda 
> "() -> fd.close()" captures 'this', not only 'fd' as can be seen by 
> running the following example:
>
> public class Test {
>
>     int x = 0;
>
>     final IntSupplier xSupplier = () -> x;
>
>     public static void main(String[] args) {
>         Test t = new Test();
>         System.out.println(t.xSupplier.getAsInt());
>         t.x = 12;
>         System.out.println(t.xSupplier.getAsInt());
>     }
> }
>
> ...which prints:
>
> 0
> 12
>
>
> To correct that, but still use lambda, you would have to capture a 
> local variable, like:
>
> public class Test {
>
>     int x = 0;
>
>     final IntSupplier xSupplier;
>
>     {
>         int xValue = x;
>         xSupplier = () -> xValue;
>     }
>
>     public static void main(String[] args) {
>         Test t = new Test();
>         System.out.println(t.xSupplier.getAsInt());
>         t.x = 12;
>         System.out.println(t.xSupplier.getAsInt());
>     }
> }
>
>
> ...now prints:
>
> 0
> 0
>
>
> Regards, Peter
>
>>




More information about the core-libs-dev mailing list