--- /dev/null 2015-06-17 09:49:50.124106881 +0200 +++ new/src/java.base/share/classes/java/lang/ref/Finalizator.java 2015-06-22 11:04:03.813381867 +0200 @@ -0,0 +1,167 @@ +package java.lang.ref; + +import java.util.Objects; +import java.util.function.Consumer; + +/** + *

Finalizator provides an alternative form of finalization which can be more + * efficiently combined with (almost) regular manual cleanup where it serves as + * a last-resort cleanup mechanism when manual cleanup is not performed. + *

+ * Instead of overriding the Object's {@link #finalize()} method, a class + * arranges in it's constructor(s) to {@link #create(Object, Consumer) create} a + * {@code Finalizator} object which is used by GC to track the reachability of + * given {@code finalizee} and invoke given {@code thunk} with it when such + * {@code finalizee} becomes unreachable. + *

+ * {@code Finalizator} can be {@link #clean() invoked} manually by user code that + * decides to perform cleanup even before GC invokes it. The 1st invocation of + * {@link #clean()} method performs the cleanup by invoking the {@code thunk}, + * subsequent invocations are ignored. + *

+ * After the cleanup is performed, the + * {@code Finalizator} is {@link #clear() cleared} which breaks the links between: + *

+ * In the absence of other links, finalizator, finalizee and thunk become + * unreachable and eligible for GC. + *

+ * Here's an example of a classic finalizable class: + *

{@code
+ *      public class Classic {
+ *          @Override
+ *          protected void finalize() {
+ *              // clean-up actions invoked at most once...
+ *          }
+ *      }
+ * }
+ *

+ * And this is an alternative using {@code Finalizator}, combining finalization + * with manual cleanup: + *

{@code
+ *      public class Alternative {
+ *          private final Finalizator finalizator =
+ *              Finalizator.create(this, Alternative::cleanup);
+ *
+ *          void cleanup() {
+ *              // clean-up actions invoked at most once...
+ *          }
+ *
+ *          // manually triggered cleanup
+ *          public void close() {
+ *              finalizator.run();
+ *          }
+ *      }
+ * }
+ * + * @param the type of finalizee tracked by Finalizator + * @since 1.9 + */ +public final class Finalizator extends Finalizer implements Cleaner { + + private Consumer thunk; + + /** + * Creates and returns an instance of Finalizator used by GC to track given + * {@code finalizee} and invoke given {@code thunk} with it when the + * finalizee becomes unreachable. + * + * @param finalizee the instance to track it's reachability + * @param thunk a {@link Consumer} which is invoked and passed the + * {@code finalizee} when it becomes unreachable. + * @param the type of {@code finalizee} + * @return a Finalizator used by GC to track given + * {@code finalizee} and invoke given {@code thunk} with it when the + * finalizee becomes unreachable + * @throws NullPointerException if either {@code finalizee} of {@code thunk} + * are null + */ + public static Finalizator create(T finalizee, Consumer thunk) { + Objects.requireNonNull(finalizee); + Objects.requireNonNull(thunk); + int rnd = nextSecondarySeed(); + int index = (rnd >>> 1) & (uncleaned.length - 1); + Finalizator finalizator = new Finalizator<>(finalizee, index, thunk); + uncleaned[index].link(finalizator, (rnd & 1) == 0); + return finalizator; + } + + private Finalizator(T finalizee, int listIndex, Consumer thunk) { + super(finalizee, listIndex); + this.thunk = thunk; + } + + /** + * Invoked by GC when the tracked finalizee becomes unreachable or + * by user code at any time. + * It invokes the finalizator's thunk with the finalizee if this + * Finalizator has not been {@link #clear() cleared} before that. If invoked + * multiple times, only the 1st invocation results in the invocation + * of the thunk. The finalizator releases the reference to the thunk and + * finalizee upon 1st invocation of this method regardless of whether + * it was performed by GC or by user code. + */ + @Override + public void clean() { + super.clean(); + } + + /** + * Invoke the {@link #thunk} passing the {@code finalizee} to it. + */ + @Override + void invokeFinalizee(T finalizee) throws Throwable { + Consumer thunk = this.thunk; + this.thunk = null; + thunk.accept(finalizee); + finalizee = null; + } + + /** + * Returns {@code null} to prevent unwanted retention of the tracked + * {@code finalizee}. + * + * @return {@code null} + */ + @Override + public T get() { + return null; + } + + /** + * Finalizator is not registered with a reference queue when created, + * so this method always returns {@code false}. + * + * @return {@code false} + */ + @Override + public boolean isEnqueued() { + return false; + } + + /** + * Finalizator is not registered with a reference queue when created, + * so this method does nothing and always returns {@code false}. + * + * @return {@code false} + */ + @Override + public boolean enqueue() { + return false; + } + + /** + * Clears this Finalizator and releases it's tracked {@code finalizee} and + * it's {@code thunk} if they have not been released yet. + * Invoking this method does not invoke the Finalizator's {@code thunk}. + * It prevents from {@link #clean() running} the {@code thunk} in the future + * if it has not been run yet. + */ + @Override + public void clear() { + super.clear(); + } +}