< prev index next >

src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java

Print this page




   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.ref;
  27 


  28 import java.lang.ref.Cleaner;
  29 import java.lang.ref.Cleaner.Cleanable;
  30 import java.lang.ref.ReferenceQueue;
  31 import java.security.AccessController;
  32 import java.security.PrivilegedAction;

  33 import java.util.concurrent.ThreadFactory;
  34 import java.util.concurrent.atomic.AtomicInteger;
  35 import java.util.function.Function;
  36 
  37 import jdk.internal.misc.InnocuousThread;
  38 
  39 /**
  40  * CleanerImpl manages a set of object references and corresponding cleaning actions.
  41  * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
  42  */
  43 public final class CleanerImpl implements Runnable {




















  44 
  45     /**
  46      * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.

  47      */
  48     private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
  49 
  50     /**
  51      * Heads of a CleanableList for each reference type.
  52      */
  53     final PhantomCleanable<?> phantomCleanableList;
  54 
  55     final WeakCleanable<?> weakCleanableList;
  56 
  57     final SoftCleanable<?> softCleanableList;
  58 
  59     // The ReferenceQueue of pending cleaning actions
  60     final ReferenceQueue<Object> queue;
  61 
  62     /**
  63      * Called by Cleaner static initialization to provide the function
  64      * to map from Cleaner to CleanerImpl.
  65      * @param access a function to map from Cleaner to CleanerImpl
  66      */
  67     public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
  68         if (cleanerImplAccess == null) {
  69             cleanerImplAccess = access;
  70         } else {
  71             throw new InternalError("cleanerImplAccess");
  72         }
  73     }
  74 
  75     /**
  76      * Called to get the CleanerImpl for a Cleaner.
  77      * @param cleaner the cleaner
  78      * @return the corresponding CleanerImpl
  79      */
  80     static CleanerImpl getCleanerImpl(Cleaner cleaner) {
  81         return cleanerImplAccess.apply(cleaner);
  82     }
  83 
  84     /**
  85      * Constructor for CleanerImpl.
  86      */
  87     public CleanerImpl() {
  88         queue = new ReferenceQueue<>();
  89         phantomCleanableList = new PhantomCleanableRef();
  90         weakCleanableList = new WeakCleanableRef();
  91         softCleanableList = new SoftCleanableRef();
  92     }
  93 
  94     /**
  95      * Starts the Cleaner implementation.
  96      * Ensure this is the CleanerImpl for the Cleaner.
  97      * When started waits for Cleanables to be queued.
  98      * @param cleaner the cleaner
  99      * @param threadFactory the thread factory
 100      */
 101     public void start(Cleaner cleaner, ThreadFactory threadFactory) {
 102         if (getCleanerImpl(cleaner) != this) {
 103             throw new AssertionError("wrong cleaner");
 104         }
 105         // schedule a nop cleaning action for the cleaner, so the associated thread
 106         // will continue to run at least until the cleaner is reclaimable.
 107         new CleanerCleanable(cleaner);
 108 
 109         if (threadFactory == null) {
 110             threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
 111         }
 112 
 113         // now that there's at least one cleaning action, for the cleaner,
 114         // we can start the associated thread, which runs until
 115         // all cleaning actions have been run.
 116         Thread thread = threadFactory.newThread(this);
 117         thread.setDaemon(true);
 118         thread.start();
 119     }
 120 
 121     /**
 122      * Process queued Cleanables as long as the cleanable lists are not empty.


 135         InnocuousThread mlThread = (t instanceof InnocuousThread)
 136                 ? (InnocuousThread) t
 137                 : null;
 138         while (!phantomCleanableList.isListEmpty() ||
 139                 !weakCleanableList.isListEmpty() ||
 140                 !softCleanableList.isListEmpty()) {
 141             if (mlThread != null) {
 142                 // Clear the thread locals
 143                 mlThread.eraseThreadLocals();
 144             }
 145             try {
 146                 // Wait for a Ref, with a timeout to avoid getting hung
 147                 // due to a race with clear/clean
 148                 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
 149                 if (ref != null) {
 150                     ref.clean();
 151                 }
 152             } catch (Throwable e) {
 153                 // ignore exceptions from the cleanup action
 154                 // (including interruption of cleanup thread)

 155             }
 156         }
 157     }
 158 
 159     /**
 160      * Perform cleaning on an unreachable PhantomReference.
 161      */
 162     public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
 163         private final Runnable action;
 164 
 165         /**
 166          * Constructor for a phantom cleanable reference.
 167          * @param obj the object to monitor
 168          * @param cleaner the cleaner
 169          * @param action the action Runnable
 170          */
 171         public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
 172             super(obj, cleaner);
 173             this.action = action;
 174         }




   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.ref;
  27 
  28 import jdk.internal.misc.InnocuousThread;
  29 
  30 import java.lang.ref.Cleaner;

  31 import java.lang.ref.ReferenceQueue;
  32 import java.security.AccessController;
  33 import java.security.PrivilegedAction;
  34 import java.util.Objects;
  35 import java.util.concurrent.ThreadFactory;
  36 import java.util.concurrent.atomic.AtomicInteger;



  37 
  38 /**
  39  * CleanerImpl is the implementation of {@link Cleaner}.

  40  */
  41 public class CleanerImpl implements Cleaner {
  42 
  43     final Task task;
  44 
  45     public CleanerImpl(ThreadFactory threadFactory) {
  46         task = new Task();
  47         task.start(this, threadFactory);
  48     }
  49 
  50     @Override
  51     public Cleanable register(Object obj, Runnable action) {
  52         Objects.requireNonNull(obj, "obj");
  53         Objects.requireNonNull(action, "action");
  54         return new CleanerImpl.PhantomCleanableRef(obj, this, action);
  55     }
  56 
  57     // package-private access to Task's state
  58     PhantomCleanable<?> phantomCleanableList() { return task.phantomCleanableList; }
  59     WeakCleanable<?> weakCleanableList() { return task.weakCleanableList; }
  60     SoftCleanable<?> softCleanableList() { return task.softCleanableList; }
  61     ReferenceQueue<Object> queue() { return task.queue; }
  62 
  63     /**
  64      * CleanerImpl.Task manages a set of object references and corresponding
  65      * cleaning actions and executes them after they are enqueued.
  66      */
  67     private static final class Task implements Runnable {

  68         /**
  69          * Heads of a CleanableList for each reference type.
  70          */
  71         final PhantomCleanable<?> phantomCleanableList;
  72 
  73         final WeakCleanable<?> weakCleanableList;
  74 
  75         final SoftCleanable<?> softCleanableList;
  76 
  77         // The ReferenceQueue of pending cleaning actions
  78         final ReferenceQueue<Object> queue;
  79 
  80         /**
  81          * Constructor for Task.















  82          */
  83         Task() {







  84             queue = new ReferenceQueue<>();
  85             phantomCleanableList = new PhantomCleanableRef();
  86             weakCleanableList = new WeakCleanableRef();
  87             softCleanableList = new SoftCleanableRef();
  88         }
  89 
  90         /**
  91          * Starts the Cleaner implementation.
  92          * Ensure this is the CleanerImpl for the Cleaner.
  93          * When started waits for Cleanables to be queued.
  94          * @param cleaner the cleaner
  95          * @param threadFactory the thread factory
  96          */
  97         void start(CleanerImpl cleaner, ThreadFactory threadFactory) {
  98             if (cleaner.task != this) {
  99                 throw new AssertionError("wrong cleaner");
 100             }
 101             // schedule a nop cleaning action for the cleaner, so the associated thread
 102             // will continue to run at least until the cleaner is reclaimable.
 103             new CleanerCleanable(cleaner);
 104 
 105             if (threadFactory == null) {
 106                 threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
 107             }
 108 
 109             // now that there's at least one cleaning action, for the cleaner,
 110             // we can start the associated thread, which runs until
 111             // all cleaning actions have been run.
 112             Thread thread = threadFactory.newThread(this);
 113             thread.setDaemon(true);
 114             thread.start();
 115         }
 116 
 117         /**
 118          * Process queued Cleanables as long as the cleanable lists are not empty.


 131             InnocuousThread mlThread = (t instanceof InnocuousThread)
 132                     ? (InnocuousThread) t
 133                     : null;
 134             while (!phantomCleanableList.isListEmpty() ||
 135                     !weakCleanableList.isListEmpty() ||
 136                     !softCleanableList.isListEmpty()) {
 137                 if (mlThread != null) {
 138                     // Clear the thread locals
 139                     mlThread.eraseThreadLocals();
 140                 }
 141                 try {
 142                     // Wait for a Ref, with a timeout to avoid getting hung
 143                     // due to a race with clear/clean
 144                     Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
 145                     if (ref != null) {
 146                         ref.clean();
 147                     }
 148                 } catch (Throwable e) {
 149                     // ignore exceptions from the cleanup action
 150                     // (including interruption of cleanup thread)
 151                 }
 152             }
 153         }
 154     }
 155 
 156     /**
 157      * Perform cleaning on an unreachable PhantomReference.
 158      */
 159     public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
 160         private final Runnable action;
 161 
 162         /**
 163          * Constructor for a phantom cleanable reference.
 164          * @param obj the object to monitor
 165          * @param cleaner the cleaner
 166          * @param action the action Runnable
 167          */
 168         public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
 169             super(obj, cleaner);
 170             this.action = action;
 171         }


< prev index next >