jdk/src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java
changeset 35004 267e4160fbe2
parent 35003 cb71f7f18b6f
parent 34989 2af91223bba9
child 35005 2dc4c11fe488
equal deleted inserted replaced
35003:cb71f7f18b6f 35004:267e4160fbe2
     1 /*
       
     2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package jdk.internal.misc;
       
    27 
       
    28 import java.lang.ref.Cleaner;
       
    29 import java.lang.ref.Cleaner.Cleanable;
       
    30 import java.lang.ref.PhantomReference;
       
    31 import java.lang.ref.Reference;
       
    32 import java.lang.ref.ReferenceQueue;
       
    33 import java.lang.ref.SoftReference;
       
    34 import java.lang.ref.WeakReference;
       
    35 import java.security.AccessController;
       
    36 import java.security.PrivilegedAction;
       
    37 import java.util.Objects;
       
    38 import java.util.concurrent.ThreadFactory;
       
    39 import java.util.function.Function;
       
    40 
       
    41 import sun.misc.InnocuousThread;
       
    42 
       
    43 /**
       
    44  * CleanerImpl manages a set of object references and corresponding cleaning actions.
       
    45  * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
       
    46  */
       
    47 public final class CleanerImpl implements Runnable {
       
    48 
       
    49     /**
       
    50      * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
       
    51      */
       
    52     private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
       
    53 
       
    54     /**
       
    55      * Heads of a CleanableList for each reference type.
       
    56      */
       
    57     final PhantomCleanable<?> phantomCleanableList;
       
    58 
       
    59     final WeakCleanable<?> weakCleanableList;
       
    60 
       
    61     final SoftCleanable<?> softCleanableList;
       
    62 
       
    63     // The ReferenceQueue of pending cleaning actions
       
    64     final ReferenceQueue<Object> queue;
       
    65 
       
    66     /**
       
    67      * Called by Cleaner static initialization to provide the function
       
    68      * to map from Cleaner to CleanerImpl.
       
    69      * @param access a function to map from Cleaner to CleanerImpl
       
    70      */
       
    71     public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
       
    72         if (cleanerImplAccess == null) {
       
    73             cleanerImplAccess = access;
       
    74         }
       
    75     }
       
    76 
       
    77     /**
       
    78      * Called to get the CleanerImpl for a Cleaner.
       
    79      * @param cleaner the cleaner
       
    80      * @return the corresponding CleanerImpl
       
    81      */
       
    82     private static CleanerImpl getCleanerImpl(Cleaner cleaner) {
       
    83         return cleanerImplAccess.apply(cleaner);
       
    84     }
       
    85 
       
    86     /**
       
    87      * Constructor for CleanerImpl.
       
    88      */
       
    89     public CleanerImpl() {
       
    90         queue = new ReferenceQueue<>();
       
    91         phantomCleanableList = new PhantomCleanableRef(this);
       
    92         weakCleanableList = new WeakCleanableRef(this);
       
    93         softCleanableList = new SoftCleanableRef(this);
       
    94     }
       
    95 
       
    96     /**
       
    97      * Starts the Cleaner implementation.
       
    98      * When started waits for Cleanables to be queued.
       
    99      * @param service the cleaner
       
   100      * @param threadFactory the thread factory
       
   101      */
       
   102     public void start(Cleaner service, ThreadFactory threadFactory) {
       
   103         // schedule a nop cleaning action for the service, so the associated thread
       
   104         // will continue to run at least until the service is reclaimable.
       
   105         new PhantomCleanableRef(service, service, () -> {});
       
   106 
       
   107         if (threadFactory == null) {
       
   108             threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
       
   109         }
       
   110 
       
   111         // now that there's at least one cleaning action, for the service,
       
   112         // we can start the associated thread, which runs until
       
   113         // all cleaning actions have been run.
       
   114         Thread thread = threadFactory.newThread(this);
       
   115         thread.setDaemon(true);
       
   116         thread.start();
       
   117     }
       
   118 
       
   119     /**
       
   120      * Process queued Cleanables as long as the cleanable lists are not empty.
       
   121      * A Cleanable is in one of the lists for each Object and for the Cleaner
       
   122      * itself.
       
   123      * Terminates when the Cleaner is no longer reachable and
       
   124      * has been cleaned and there are no more Cleanable instances
       
   125      * for which the object is reachable.
       
   126      * <p>
       
   127      * If the thread is a ManagedLocalsThread, the threadlocals
       
   128      * are erased before each cleanup
       
   129      */
       
   130     public void run() {
       
   131         Thread t = Thread.currentThread();
       
   132         InnocuousThread mlThread = (t instanceof InnocuousThread)
       
   133                 ? (InnocuousThread) t
       
   134                 : null;
       
   135         while (!phantomCleanableList.isListEmpty() ||
       
   136                 !weakCleanableList.isListEmpty() ||
       
   137                 !softCleanableList.isListEmpty()) {
       
   138             if (mlThread != null) {
       
   139                 // Clear the thread locals
       
   140                 mlThread.eraseThreadLocals();
       
   141             }
       
   142             try {
       
   143                 // Wait for a Ref, with a timeout to avoid getting hung
       
   144                 // due to a race with clear/clean
       
   145                 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
       
   146                 if (ref != null) {
       
   147                     ref.clean();
       
   148                 }
       
   149             } catch (InterruptedException i) {
       
   150                 continue;   // ignore the interruption
       
   151             } catch (Throwable e) {
       
   152                 // ignore exceptions from the cleanup action
       
   153             }
       
   154         }
       
   155     }
       
   156 
       
   157     /**
       
   158      * PhantomCleanable subclasses efficiently encapsulate cleanup state and
       
   159      * the cleaning action.
       
   160      * Subclasses implement the abstract {@link #performCleanup()}  method
       
   161      * to provide the cleaning action.
       
   162      * When constructed, the object reference and the {@link Cleanable Cleanable}
       
   163      * are registered with the {@link Cleaner}.
       
   164      * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
       
   165      * referent becomes phantom reachable.
       
   166      */
       
   167     public static abstract class PhantomCleanable<T> extends PhantomReference<T>
       
   168             implements Cleaner.Cleanable {
       
   169 
       
   170         /**
       
   171          * Links to previous and next in a doubly-linked list.
       
   172          */
       
   173         PhantomCleanable<?> prev = this, next = this;
       
   174 
       
   175         /**
       
   176          * The CleanerImpl for this Cleanable.
       
   177          */
       
   178         private final CleanerImpl cleanerImpl;
       
   179 
       
   180         /**
       
   181          * Constructs new {@code PhantomCleanable} with
       
   182          * {@code non-null referent} and {@code non-null cleaner}.
       
   183          * The {@code cleaner} is not retained; it is only used to
       
   184          * register the newly constructed {@link Cleaner.Cleanable Cleanable}.
       
   185          *
       
   186          * @param referent the referent to track
       
   187          * @param cleaner  the {@code Cleaner} to register with
       
   188          */
       
   189         public PhantomCleanable(T referent, Cleaner cleaner) {
       
   190             super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue);
       
   191             this.cleanerImpl = getCleanerImpl(cleaner);
       
   192             insert();
       
   193 
       
   194             // TODO: Replace getClass() with ReachabilityFence when it is available
       
   195             cleaner.getClass();
       
   196             referent.getClass();
       
   197         }
       
   198 
       
   199         /**
       
   200          * Construct a new root of the list; not inserted.
       
   201          */
       
   202         PhantomCleanable(CleanerImpl cleanerImpl) {
       
   203             super(null, null);
       
   204             this.cleanerImpl = cleanerImpl;
       
   205         }
       
   206 
       
   207         /**
       
   208          * Insert this PhantomCleanable after the list head.
       
   209          */
       
   210         private void insert() {
       
   211             final PhantomCleanable<?> list = cleanerImpl.phantomCleanableList;
       
   212             synchronized (list) {
       
   213                 prev = list;
       
   214                 next = list.next;
       
   215                 next.prev = this;
       
   216                 list.next = this;
       
   217             }
       
   218         }
       
   219 
       
   220         /**
       
   221          * Remove this PhantomCleanable from the list.
       
   222          *
       
   223          * @return true if Cleanable was removed or false if not because
       
   224          * it had already been removed before
       
   225          */
       
   226         private boolean remove() {
       
   227             PhantomCleanable<?> list = cleanerImpl.phantomCleanableList;
       
   228             synchronized (list) {
       
   229                 if (next != this) {
       
   230                     next.prev = prev;
       
   231                     prev.next = next;
       
   232                     prev = this;
       
   233                     next = this;
       
   234                     return true;
       
   235                 }
       
   236                 return false;
       
   237             }
       
   238         }
       
   239 
       
   240         /**
       
   241          * Returns true if the list's next reference refers to itself.
       
   242          *
       
   243          * @return true if the list is empty
       
   244          */
       
   245         boolean isListEmpty() {
       
   246             PhantomCleanable<?> list = cleanerImpl.phantomCleanableList;
       
   247             synchronized (list) {
       
   248                 return list == list.next;
       
   249             }
       
   250         }
       
   251 
       
   252         /**
       
   253          * Unregister this PhantomCleanable and invoke {@link #performCleanup()},
       
   254          * ensuring at-most-once semantics.
       
   255          */
       
   256         @Override
       
   257         public final void clean() {
       
   258             if (remove()) {
       
   259                 super.clear();
       
   260                 performCleanup();
       
   261             }
       
   262         }
       
   263 
       
   264         /**
       
   265          * Unregister this PhantomCleanable and clear the reference.
       
   266          * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
       
   267          */
       
   268         @Override
       
   269         public void clear() {
       
   270             if (remove()) {
       
   271                 super.clear();
       
   272             }
       
   273         }
       
   274 
       
   275         /**
       
   276          * The {@code performCleanup} abstract method is overridden
       
   277          * to implement the cleaning logic.
       
   278          * The {@code performCleanup} method should not be called except
       
   279          * by the {@link #clean} method which ensures at most once semantics.
       
   280          */
       
   281         protected abstract void performCleanup();
       
   282 
       
   283         /**
       
   284          * This method always throws {@link UnsupportedOperationException}.
       
   285          * Enqueuing details of {@link Cleaner.Cleanable}
       
   286          * are a private implementation detail.
       
   287          *
       
   288          * @throws UnsupportedOperationException always
       
   289          */
       
   290         @Override
       
   291         public final boolean isEnqueued() {
       
   292             throw new UnsupportedOperationException("isEnqueued");
       
   293         }
       
   294 
       
   295         /**
       
   296          * This method always throws {@link UnsupportedOperationException}.
       
   297          * Enqueuing details of {@link Cleaner.Cleanable}
       
   298          * are a private implementation detail.
       
   299          *
       
   300          * @throws UnsupportedOperationException always
       
   301          */
       
   302         @Override
       
   303         public final boolean enqueue() {
       
   304             throw new UnsupportedOperationException("enqueue");
       
   305         }
       
   306     }
       
   307 
       
   308     /**
       
   309      * WeakCleanable subclasses efficiently encapsulate cleanup state and
       
   310      * the cleaning action.
       
   311      * Subclasses implement the abstract {@link #performCleanup()}  method
       
   312      * to provide the cleaning action.
       
   313      * When constructed, the object reference and the {@link Cleanable Cleanable}
       
   314      * are registered with the {@link Cleaner}.
       
   315      * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
       
   316      * referent becomes weakly reachable.
       
   317      */
       
   318     public static abstract class WeakCleanable<T> extends WeakReference<T>
       
   319             implements Cleaner.Cleanable {
       
   320 
       
   321         /**
       
   322          * Links to previous and next in a doubly-linked list.
       
   323          */
       
   324         WeakCleanable<?> prev = this, next = this;
       
   325 
       
   326         /**
       
   327          * The CleanerImpl for this Cleanable.
       
   328          */
       
   329         private final CleanerImpl cleanerImpl;
       
   330 
       
   331         /**
       
   332          * Constructs new {@code WeakCleanableReference} with
       
   333          * {@code non-null referent} and {@code non-null cleaner}.
       
   334          * The {@code cleaner} is not retained by this reference; it is only used
       
   335          * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
       
   336          *
       
   337          * @param referent the referent to track
       
   338          * @param cleaner  the {@code Cleaner} to register new reference with
       
   339          */
       
   340         public WeakCleanable(T referent, Cleaner cleaner) {
       
   341             super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue);
       
   342             cleanerImpl = getCleanerImpl(cleaner);
       
   343             insert();
       
   344 
       
   345             // TODO: Replace getClass() with ReachabilityFence when it is available
       
   346             cleaner.getClass();
       
   347             referent.getClass();
       
   348         }
       
   349 
       
   350         /**
       
   351          * Construct a new root of the list; not inserted.
       
   352          */
       
   353         WeakCleanable(CleanerImpl cleanerImpl) {
       
   354             super(null, null);
       
   355             this.cleanerImpl = cleanerImpl;
       
   356         }
       
   357 
       
   358         /**
       
   359          * Insert this WeakCleanableReference after the list head.
       
   360          */
       
   361         private void insert() {
       
   362             final WeakCleanable<?> list = cleanerImpl.weakCleanableList;
       
   363             synchronized (list) {
       
   364                 prev = list;
       
   365                 next = list.next;
       
   366                 next.prev = this;
       
   367                 list.next = this;
       
   368             }
       
   369         }
       
   370 
       
   371         /**
       
   372          * Remove this WeakCleanableReference from the list.
       
   373          *
       
   374          * @return true if Cleanable was removed or false if not because
       
   375          * it had already been removed before
       
   376          */
       
   377         private boolean remove() {
       
   378             WeakCleanable<?> list = cleanerImpl.weakCleanableList;
       
   379             synchronized (list) {
       
   380                 if (next != this) {
       
   381                     next.prev = prev;
       
   382                     prev.next = next;
       
   383                     prev = this;
       
   384                     next = this;
       
   385                     return true;
       
   386                 }
       
   387                 return false;
       
   388             }
       
   389         }
       
   390 
       
   391         /**
       
   392          * Returns true if the list's next reference refers to itself.
       
   393          *
       
   394          * @return true if the list is empty
       
   395          */
       
   396         boolean isListEmpty() {
       
   397             WeakCleanable<?> list = cleanerImpl.weakCleanableList;
       
   398             synchronized (list) {
       
   399                 return list == list.next;
       
   400             }
       
   401         }
       
   402 
       
   403         /**
       
   404          * Unregister this WeakCleanable reference and invoke {@link #performCleanup()},
       
   405          * ensuring at-most-once semantics.
       
   406          */
       
   407         @Override
       
   408         public final void clean() {
       
   409             if (remove()) {
       
   410                 super.clear();
       
   411                 performCleanup();
       
   412             }
       
   413         }
       
   414 
       
   415         /**
       
   416          * Unregister this WeakCleanable and clear the reference.
       
   417          * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
       
   418          */
       
   419         @Override
       
   420         public void clear() {
       
   421             if (remove()) {
       
   422                 super.clear();
       
   423             }
       
   424         }
       
   425 
       
   426         /**
       
   427          * The {@code performCleanup} abstract method is overridden
       
   428          * to implement the cleaning logic.
       
   429          * The {@code performCleanup} method should not be called except
       
   430          * by the {@link #clean} method which ensures at most once semantics.
       
   431          */
       
   432         protected abstract void performCleanup();
       
   433 
       
   434         /**
       
   435          * This method always throws {@link UnsupportedOperationException}.
       
   436          * Enqueuing details of {@link java.lang.ref.Cleaner.Cleanable}
       
   437          * are a private implementation detail.
       
   438          *
       
   439          * @throws UnsupportedOperationException always
       
   440          */
       
   441         @Override
       
   442         public final boolean isEnqueued() {
       
   443             throw new UnsupportedOperationException("isEnqueued");
       
   444         }
       
   445 
       
   446         /**
       
   447          * This method always throws {@link UnsupportedOperationException}.
       
   448          * Enqueuing details of {@link java.lang.ref.Cleaner.Cleanable}
       
   449          * are a private implementation detail.
       
   450          *
       
   451          * @throws UnsupportedOperationException always
       
   452          */
       
   453         @Override
       
   454         public final boolean enqueue() {
       
   455             throw new UnsupportedOperationException("enqueue");
       
   456         }
       
   457     }
       
   458 
       
   459     /**
       
   460      * SoftCleanable subclasses efficiently encapsulate cleanup state and
       
   461      * the cleaning action.
       
   462      * Subclasses implement the abstract {@link #performCleanup()}  method
       
   463      * to provide the cleaning action.
       
   464      * When constructed, the object reference and the {@link Cleanable Cleanable}
       
   465      * are registered with the {@link Cleaner}.
       
   466      * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
       
   467      * referent becomes softly reachable.
       
   468      */
       
   469     public static abstract class SoftCleanable<T> extends SoftReference<T>
       
   470             implements Cleaner.Cleanable {
       
   471 
       
   472         /**
       
   473          * Links to previous and next in a doubly-linked list.
       
   474          */
       
   475         SoftCleanable<?> prev = this, next = this;
       
   476 
       
   477         /**
       
   478          * The CleanerImpl for this Cleanable.
       
   479          */
       
   480         private final CleanerImpl cleanerImpl;
       
   481 
       
   482         /**
       
   483          * Constructs new {@code SoftCleanableReference} with
       
   484          * {@code non-null referent} and {@code non-null cleaner}.
       
   485          * The {@code cleaner} is not retained by this reference; it is only used
       
   486          * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
       
   487          *
       
   488          * @param referent the referent to track
       
   489          * @param cleaner  the {@code Cleaner} to register with
       
   490          */
       
   491         public SoftCleanable(T referent, Cleaner cleaner) {
       
   492             super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue);
       
   493             cleanerImpl = getCleanerImpl(cleaner);
       
   494             insert();
       
   495 
       
   496             // TODO: Replace getClass() with ReachabilityFence when it is available
       
   497             cleaner.getClass();
       
   498             referent.getClass();
       
   499         }
       
   500 
       
   501         /**
       
   502          * Construct a new root of the list; not inserted.
       
   503          */
       
   504         SoftCleanable(CleanerImpl cleanerImpl) {
       
   505             super(null, null);
       
   506             this.cleanerImpl = cleanerImpl;
       
   507         }
       
   508 
       
   509         /**
       
   510          * Insert this SoftCleanableReference after the list head.
       
   511          */
       
   512         private void insert() {
       
   513             final SoftCleanable<?> list = cleanerImpl.softCleanableList;
       
   514             synchronized (list) {
       
   515                 prev = list;
       
   516                 next = list.next;
       
   517                 next.prev = this;
       
   518                 list.next = this;
       
   519             }
       
   520         }
       
   521 
       
   522         /**
       
   523          * Remove this SoftCleanableReference from the list.
       
   524          *
       
   525          * @return true if Cleanable was removed or false if not because
       
   526          * it had already been removed before
       
   527          */
       
   528         private boolean remove() {
       
   529             SoftCleanable<?> list = cleanerImpl.softCleanableList;
       
   530             synchronized (list) {
       
   531                 if (next != this) {
       
   532                     next.prev = prev;
       
   533                     prev.next = next;
       
   534                     prev = this;
       
   535                     next = this;
       
   536                     return true;
       
   537                 }
       
   538                 return false;
       
   539             }
       
   540         }
       
   541 
       
   542         /**
       
   543          * Returns true if the list's next reference refers to itself.
       
   544          *
       
   545          * @return true if the list is empty
       
   546          */
       
   547         boolean isListEmpty() {
       
   548             SoftCleanable<?> list = cleanerImpl.softCleanableList;
       
   549             synchronized (list) {
       
   550                 return list == list.next;
       
   551             }
       
   552         }
       
   553 
       
   554         /**
       
   555          * Unregister this SoftCleanable reference and invoke {@link #performCleanup()},
       
   556          * ensuring at-most-once semantics.
       
   557          */
       
   558         @Override
       
   559         public final void clean() {
       
   560             if (remove()) {
       
   561                 super.clear();
       
   562                 performCleanup();
       
   563             }
       
   564         }
       
   565 
       
   566         /**
       
   567          * Unregister this SoftCleanable and clear the reference.
       
   568          * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
       
   569          */
       
   570         @Override
       
   571         public void clear() {
       
   572             if (remove()) {
       
   573                 super.clear();
       
   574             }
       
   575         }
       
   576 
       
   577         /**
       
   578          * The {@code performCleanup} abstract method is overridden
       
   579          * to implement the cleaning logic.
       
   580          * The {@code performCleanup} method should not be called except
       
   581          * by the {@link #clean} method which ensures at most once semantics.
       
   582          */
       
   583         protected abstract void performCleanup();
       
   584 
       
   585         /**
       
   586          * This method always throws {@link UnsupportedOperationException}.
       
   587          * Enqueuing details of {@link Cleaner.Cleanable}
       
   588          * are a private implementation detail.
       
   589          *
       
   590          * @throws UnsupportedOperationException always
       
   591          */
       
   592         @Override
       
   593         public final boolean isEnqueued() {
       
   594             throw new UnsupportedOperationException("isEnqueued");
       
   595         }
       
   596 
       
   597         /**
       
   598          * This method always throws {@link UnsupportedOperationException}.
       
   599          * Enqueuing details of {@link Cleaner.Cleanable}
       
   600          * are a private implementation detail.
       
   601          *
       
   602          * @throws UnsupportedOperationException always
       
   603          */
       
   604         @Override
       
   605         public final boolean enqueue() {
       
   606             throw new UnsupportedOperationException("enqueue");
       
   607         }
       
   608     }
       
   609 
       
   610     /**
       
   611      * Perform cleaning on an unreachable PhantomReference.
       
   612      */
       
   613     public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
       
   614         private final Runnable action;
       
   615 
       
   616         /**
       
   617          * Constructor for a phantom cleanable reference.
       
   618          * @param obj the object to monitor
       
   619          * @param cleaner the cleaner
       
   620          * @param action the action Runnable
       
   621          */
       
   622         public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
       
   623             super(obj, cleaner);
       
   624             this.action = action;
       
   625         }
       
   626 
       
   627         /**
       
   628          * Constructor used only for root of phantom cleanable list.
       
   629          * @param cleanerImpl  the cleanerImpl
       
   630          */
       
   631         PhantomCleanableRef(CleanerImpl cleanerImpl) {
       
   632             super(cleanerImpl);
       
   633             this.action = null;
       
   634         }
       
   635 
       
   636         @Override
       
   637         protected void performCleanup() {
       
   638             action.run();
       
   639         }
       
   640 
       
   641         /**
       
   642          * Prevent access to referent even when it is still alive.
       
   643          *
       
   644          * @throws UnsupportedOperationException always
       
   645          */
       
   646         @Override
       
   647         public Object get() {
       
   648             throw new UnsupportedOperationException("get");
       
   649         }
       
   650 
       
   651         /**
       
   652          * Direct clearing of the referent is not supported.
       
   653          *
       
   654          * @throws UnsupportedOperationException always
       
   655          */
       
   656         @Override
       
   657         public void clear() {
       
   658             throw new UnsupportedOperationException("clear");
       
   659         }
       
   660     }
       
   661 
       
   662     /**
       
   663      * Perform cleaning on an unreachable WeakReference.
       
   664      */
       
   665     public static final class WeakCleanableRef extends WeakCleanable<Object> {
       
   666         private final Runnable action;
       
   667 
       
   668         /**
       
   669          * Constructor for a weak cleanable reference.
       
   670          * @param obj the object to monitor
       
   671          * @param cleaner the cleaner
       
   672          * @param action the action Runnable
       
   673          */
       
   674         WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
       
   675             super(obj, cleaner);
       
   676             this.action = action;
       
   677         }
       
   678 
       
   679         /**
       
   680          * Constructor used only for root of weak cleanable list.
       
   681          * @param cleanerImpl  the cleanerImpl
       
   682          */
       
   683         WeakCleanableRef(CleanerImpl cleanerImpl) {
       
   684             super(cleanerImpl);
       
   685             this.action = null;
       
   686         }
       
   687 
       
   688         @Override
       
   689         protected void performCleanup() {
       
   690             action.run();
       
   691         }
       
   692 
       
   693         /**
       
   694          * Prevent access to referent even when it is still alive.
       
   695          *
       
   696          * @throws UnsupportedOperationException always
       
   697          */
       
   698         @Override
       
   699         public Object get() {
       
   700             throw new UnsupportedOperationException("get");
       
   701         }
       
   702 
       
   703         /**
       
   704          * Direct clearing of the referent is not supported.
       
   705          *
       
   706          * @throws UnsupportedOperationException always
       
   707          */
       
   708         @Override
       
   709         public void clear() {
       
   710             throw new UnsupportedOperationException("clear");
       
   711         }
       
   712     }
       
   713 
       
   714     /**
       
   715      * Perform cleaning on an unreachable SoftReference.
       
   716      */
       
   717     public static final class SoftCleanableRef extends SoftCleanable<Object> {
       
   718         private final Runnable action;
       
   719 
       
   720         /**
       
   721          * Constructor for a soft cleanable reference.
       
   722          * @param obj the object to monitor
       
   723          * @param cleaner the cleaner
       
   724          * @param action the action Runnable
       
   725          */
       
   726         SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
       
   727             super(obj, cleaner);
       
   728             this.action = action;
       
   729         }
       
   730 
       
   731         /**
       
   732          * Constructor used only for root of soft cleanable list.
       
   733          * @param cleanerImpl  the cleanerImpl
       
   734          */
       
   735         SoftCleanableRef(CleanerImpl cleanerImpl) {
       
   736             super(cleanerImpl);
       
   737             this.action = null;
       
   738         }
       
   739 
       
   740         @Override
       
   741         protected void performCleanup() {
       
   742             action.run();
       
   743         }
       
   744 
       
   745         /**
       
   746          * Prevent access to referent even when it is still alive.
       
   747          *
       
   748          * @throws UnsupportedOperationException always
       
   749          */
       
   750         @Override
       
   751         public Object get() {
       
   752             throw new UnsupportedOperationException("get");
       
   753         }
       
   754 
       
   755         /**
       
   756          * Direct clearing of the referent is not supported.
       
   757          *
       
   758          * @throws UnsupportedOperationException always
       
   759          */
       
   760         @Override
       
   761         public void clear() {
       
   762             throw new UnsupportedOperationException("clear");
       
   763         }
       
   764 
       
   765     }
       
   766 
       
   767     /**
       
   768      * A ThreadFactory for InnocuousThreads.
       
   769      * The factory is a singleton.
       
   770      */
       
   771     static final class InnocuousThreadFactory implements ThreadFactory {
       
   772         final static ThreadFactory factory = new InnocuousThreadFactory();
       
   773 
       
   774         static ThreadFactory factory() {
       
   775             return factory;
       
   776         }
       
   777 
       
   778         public Thread newThread(Runnable r) {
       
   779             return AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
       
   780                 Thread t = new InnocuousThread(r);
       
   781                 t.setPriority(Thread.MAX_PRIORITY - 2);
       
   782                 t.setName("Cleaner-" + t.getId());
       
   783                 return t;
       
   784             });
       
   785         }
       
   786     }
       
   787 
       
   788 }