Hi again,
On 10/30/17 21:34, Peter Levart wrote:
To mimic the finalization registration, it might be a good to
encourage the following coding pattern (using Inflater/ZStreamRef just
as an example, not suggesting to do that here unless you like it):
class ZStreamRef implements Runnable {
private final LongConsumer end;
private volatile long address;
final Cleaner.Cleanable cleanable; // move cleanable from
Inflater/Deflater to here
ZStreamRef (Object reference, LongSupplier init, LongConsumer end) {
// perform registration as 1st thing in constructor
cleanable = CleanerFactory.cleaner().register(reference, this);
this.end = end;
this.address = init.getAsLong();
}
long address() {
return address;
}
public synchronized void run() {
long addr = address;
address = 0;
if (addr != 0) {
end.accept(addr);
}
}
}
...above example lends itself as a use case for the following equivalent
alternative using internal low-level API where ZStreamRef becomes the
Cleanable itself:
class ZStreamRef extends PhantomCleanable<Object> {
private final LongConsumer end;
private volatile long address;
ZStreamRef (Object referent, LongSupplier init, LongConsumer end) {
// here the registration MUST happen as 1st thing - enforced by
javac
super(referent, CleanerFactory.cleaner());
this.end = end;
this.address = init.getAsLong();
}
long address() {
return address;
}
@Override
protected void performCleanup() {
long addr = address;
address = 0;
if (addr != 0) {
end.accept(addr);
}
}
}
Inflater/Deflater constructor is unchanged while end() becomes:
public void end() {
synchronized (zsRef) {
zsRef.clean(); // zsRef is-a Cleanable
buf = null;
}
}
It's interesting that something that is considered a "low-level" API in
above example forces you to do it right, while the high level API doesn't.
Regards, Peter