--- old/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2017-10-31 23:27:36.526566457 +0100 +++ new/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2017-10-31 23:27:36.404568535 +0100 @@ -25,6 +25,8 @@ package jdk.internal.ref; +import jdk.internal.misc.InnocuousThread; + import java.lang.ref.Cleaner; import java.lang.ref.Cleaner.Cleanable; import java.lang.ref.ReferenceQueue; @@ -32,9 +34,11 @@ import java.security.PrivilegedAction; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import java.util.function.Function; - -import jdk.internal.misc.InnocuousThread; +import java.util.function.LongConsumer; +import java.util.function.LongSupplier; +import java.util.function.Supplier; /** * CleanerImpl manages a set of object references and corresponding cleaning actions. @@ -187,6 +191,171 @@ } /** + * Prevent access to referent even when it is still alive. + * + * @throws UnsupportedOperationException always + */ + @Override + public Object get() { + throw new UnsupportedOperationException("get"); + } + + /** + * Direct clearing of the referent is not supported. + * + * @throws UnsupportedOperationException always + */ + @Override + public void clear() { + throw new UnsupportedOperationException("clear"); + } + } + + /** + * Reference-valued resource, automatically cleaned when + * the tracked referent becomes phantom-reachable. + * + * @param the type of resource + * @since 10 + */ + public static final class PhantomCleanableResource + extends PhantomCleanable + implements Cleaner.CleanableResource { + + private final T resource; + private Consumer deallocator; + + /** + * Constructor for a phantom cleanable resource. + * @param obj the object to monitor + * @param cleaner the cleaner + * @param allocator the resource allocator function + * @param deallocator the resource de-allocator function + */ + public PhantomCleanableResource(Object obj, Cleaner cleaner, + Supplier allocator, + Consumer deallocator) { + super(obj, cleaner); + try { + this.resource = allocator.get(); + } catch (Throwable t) { + // effectively de-register this cleanable in case + // resource allocation fails + super.clear(); + throw t; + } + this.deallocator = deallocator; + } + + + @Override + protected void performCleanup() { + Consumer deallocator = this.deallocator; + // only when deallocator was assigned, we can be sure that + // allocator.get() returned successfully + if (deallocator != null) { + // mark that cleanup has been performed + this.deallocator = null; + deallocator.accept(resource); + } + } + + /** + * Access to the allocated resource. + * + * @return the allocated resource + */ + @Override + public T value() { + if (deallocator == null) { + throw new IllegalStateException("Already cleaned"); + } + return resource; + } + + /** + * Prevent access to referent even when it is still alive. + * + * @throws UnsupportedOperationException always + */ + @Override + public Object get() { + throw new UnsupportedOperationException("get"); + } + + /** + * Direct clearing of the referent is not supported. + * + * @throws UnsupportedOperationException always + */ + @Override + public void clear() { + throw new UnsupportedOperationException("clear"); + } + } + + /** + * Long-valued resource, automatically cleaned when + * the tracked referent becomes phantom-reachable. + * + * @since 10 + */ + public static final class PhantomLongCleanableResource + extends PhantomCleanable + implements Cleaner.LongCleanableResource { + + private final long resource; + private LongConsumer deallocator; + + /** + * Constructor for a phantom cleanable resource. + * @param obj the object to monitor + * @param cleaner the cleaner + * @param allocator the resource allocator function + * @param deallocator the resource de-allocator function + */ + public PhantomLongCleanableResource(Object obj, Cleaner cleaner, + LongSupplier allocator, + LongConsumer deallocator) { + super(obj, cleaner); + try { + this.resource = allocator.getAsLong(); + } catch (Throwable t) { + // effectively de-register this cleanable in case + // resource allocation fails + super.clear(); + throw t; + } + this.deallocator = deallocator; + } + + + @Override + protected void performCleanup() { + LongConsumer deallocator = this.deallocator; + // only when deallocator was assigned, we can be sure that + // allocator.get() returned successfully + if (deallocator != null) { + // mark that cleanup has been performed + this.deallocator = null; + deallocator.accept(resource); + } + } + + /** + * Access to the allocated resource. + * + * @return the allocated resource + */ + @Override + public long value() { + if (deallocator == null) { + throw new IllegalStateException("Already cleaned"); + } + return resource; + } + + /** * Prevent access to referent even when it is still alive. * * @throws UnsupportedOperationException always