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