< prev index next >

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

Print this page




  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 import jdk.internal.misc.JavaLangRefAccess;
  30 import jdk.internal.misc.SharedSecrets;
  31 import jdk.internal.vm.annotation.ReservedStackAccess;
  32 
  33 import java.lang.ref.Cleaner;
  34 import java.lang.ref.ReferenceQueue;
  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.concurrent.atomic.AtomicInteger;
  40 import java.util.concurrent.locks.StampedLock;
  41 import java.util.function.BooleanSupplier;
  42 
  43 /**
  44  * CleanerImpl is the implementation of {@link Cleaner}.
  45  */
  46 public class CleanerImpl implements Cleaner {
  47 
  48     final Task task;
  49 
  50     public CleanerImpl(ThreadFactory threadFactory) {
  51         task = new Task();
  52         task.start(this, threadFactory);
  53     }
  54 
  55     @Override
  56     public Cleanable register(Object obj, Runnable action) {
  57         Objects.requireNonNull(obj, "obj");
  58         Objects.requireNonNull(action, "action");
  59         return new CleanerImpl.PhantomCleanableRef(obj, this, action);
  60     }
  61 
  62     /**
  63      * CleanerImpl.ExtendedImpl is the implementation of {@link ExtendedCleaner}.
  64      */
  65     static class ExtendedImpl extends CleanerImpl implements ExtendedCleaner {
  66 
  67         ExtendedImpl(ThreadFactory threadFactory) {
  68             super(threadFactory);
  69         }
  70 
  71         // A fair lock for threads that retry actions to queue after
  72         // 1st optimistic try fails so that only a single thread at a time is
  73         // retrying actions while helping the Cleaner execute Cleanable(s)
  74         // and trigger new Reference discovery before finally giving up.
  75         private final StampedLock helpingLock = new StampedLock();
  76 
  77         public boolean retryWhileHelpingClean(BooleanSupplier retriableAction) {


  78             // 1st optimistic try - allow concurrent execution of actions
  79             // until helping is necessary
  80             long stamp = helpingLock.tryReadLock();
  81             if (stamp != 0) try {
  82                 if (retriableAction.getAsBoolean()) {
  83                     return true;
  84                 }
  85             } finally {
  86                 helpingLock.unlockRead(stamp);
  87             }
  88 
  89             // retrials with helping are exclusive
  90             stamp = helpingLock.writeLock();
  91             try {
  92                 // retry actions while executing enqueued Cleanable(s) until the
  93                 // queue drains out
  94                 do {
  95                     if (retriableAction.getAsBoolean()) {
  96                         return true;
  97                     }
  98                 } while (task.cleanNextEnqueued());
  99 
 100                 // the queue is now empty but there may have been a long time
 101                 // since last Reference discovery has been performed.
 102                 JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
 103                 // trigger Reference(s) discovery
 104                 int discoveryPhase = jlra.discoverReferences();
 105                 // wait for newly discovered Reference(s) to be enqueued
 106                 boolean interrupted = false;
 107                 try {
 108                     while (true) {
 109                         try {
 110                             jlra.awaitReferencesEnqueued(discoveryPhase);
 111                             break;
 112                         } catch (InterruptedException e) {
 113                             // ignore interrupts but don't swallow them
 114                             interrupted = true;
 115                         }
 116                     }
 117                 } finally {
 118                     if (interrupted) {
 119                         Thread.currentThread().interrupt();
 120                     }
 121                 }
 122 
 123                 // the queue is now hopefully filled with some freshly discovered
 124                 // Cleanable(s) so retry operation while executing enqueued Cleanable(s)
 125                 // until the queue drains out
 126                 do {
 127                     if (retriableAction.getAsBoolean()) {
 128                         return true;
 129                     }
 130                 } while (task.cleanNextEnqueued());
 131 
 132                 // give up finally
 133                 return false;
 134             } finally {
 135                 helpingLock.unlockWrite(stamp);
 136             }
 137         }
 138     }
 139 
 140     // package-private access to Task's state
 141     PhantomCleanable<?> phantomCleanableList() { return task.phantomCleanableList; }
 142     WeakCleanable<?> weakCleanableList() { return task.weakCleanableList; }
 143     SoftCleanable<?> softCleanableList() { return task.softCleanableList; }
 144     ReferenceQueue<Object> queue() { return task.queue; }
 145 
 146     /**
 147      * CleanerImpl.Task manages a set of object references and corresponding
 148      * cleaning actions and executes them after they are enqueued.
 149      */
 150     private static final class Task implements Runnable {
 151         /**
 152          * Heads of a CleanableList for each reference type.
 153          */




  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 import jdk.internal.misc.JavaLangRefAccess;
  30 import jdk.internal.misc.SharedSecrets;
  31 import jdk.internal.vm.annotation.ReservedStackAccess;
  32 
  33 import java.lang.ref.Cleaner;
  34 import java.lang.ref.ReferenceQueue;
  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.concurrent.atomic.AtomicInteger;
  40 import java.util.concurrent.locks.StampedLock;
  41 import java.util.function.Supplier;
  42 
  43 /**
  44  * CleanerImpl is the implementation of {@link Cleaner}.
  45  */
  46 public class CleanerImpl implements Cleaner {
  47 
  48     final Task task;
  49 
  50     public CleanerImpl(ThreadFactory threadFactory) {
  51         task = new Task();
  52         task.start(this, threadFactory);
  53     }
  54 
  55     @Override
  56     public Cleanable register(Object obj, Runnable action) {
  57         Objects.requireNonNull(obj, "obj");
  58         Objects.requireNonNull(action, "action");
  59         return new CleanerImpl.PhantomCleanableRef(obj, this, action);
  60     }
  61 
  62     /**
  63      * CleanerImpl.ExtendedImpl is the implementation of {@link ExtendedCleaner}.
  64      */
  65     static class ExtendedImpl extends CleanerImpl implements ExtendedCleaner {
  66 
  67         ExtendedImpl(ThreadFactory threadFactory) {
  68             super(threadFactory);
  69         }
  70 
  71         // A fair lock for threads that retry actions to queue after
  72         // 1st optimistic try fails so that only a single thread at a time is
  73         // retrying actions while helping the Cleaner execute Cleanable(s)
  74         // and trigger new Reference discovery before finally giving up.
  75         private final StampedLock helpingLock = new StampedLock();
  76 
  77         @Override
  78         public <T> T retryWhileHelpingClean(Supplier<T> retriableAction) {
  79             T result;
  80             // 1st optimistic try - allow concurrent execution of actions
  81             // until helping is necessary
  82             long stamp = helpingLock.tryReadLock();
  83             if (stamp != 0) try {
  84                 if ((result = retriableAction.get()) != null) {
  85                     return result;
  86                 }
  87             } finally {
  88                 helpingLock.unlockRead(stamp);
  89             }
  90 
  91             // retrials with helping are exclusive
  92             stamp = helpingLock.writeLock();
  93             try {
  94                 // retry action while executing enqueued Cleanable(s) until the
  95                 // queue drains out
  96                 do {
  97                     if ((result = retriableAction.get()) != null) {
  98                         return result;
  99                     }
 100                 } while (task.cleanNextEnqueued());
 101 
 102                 // the queue is now empty but there may have been a long time
 103                 // since last Reference discovery has been performed.
 104                 JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
 105                 // trigger Reference(s) discovery
 106                 int discoveryPhase = jlra.discoverReferences();
 107                 // wait for newly discovered Reference(s) to be enqueued
 108                 boolean interrupted = false;
 109                 try {
 110                     while (true) {
 111                         try {
 112                             jlra.awaitReferencesEnqueued(discoveryPhase);
 113                             break;
 114                         } catch (InterruptedException e) {
 115                             // ignore interrupts but don't swallow them
 116                             interrupted = true;
 117                         }
 118                     }
 119                 } finally {
 120                     if (interrupted) {
 121                         Thread.currentThread().interrupt();
 122                     }
 123                 }
 124 
 125                 // the queue is now hopefully filled with some freshly discovered
 126                 // Cleanable(s) so retry operation while executing enqueued Cleanable(s)
 127                 // until the queue drains out
 128                 do {
 129                     if ((result = retriableAction.get()) != null) {
 130                         return result;
 131                     }
 132                 } while (task.cleanNextEnqueued());
 133 
 134                 // give up finally
 135                 return null;
 136             } finally {
 137                 helpingLock.unlockWrite(stamp);
 138             }
 139         }
 140     }
 141 
 142     // package-private access to Task's state
 143     PhantomCleanable<?> phantomCleanableList() { return task.phantomCleanableList; }
 144     WeakCleanable<?> weakCleanableList() { return task.weakCleanableList; }
 145     SoftCleanable<?> softCleanableList() { return task.softCleanableList; }
 146     ReferenceQueue<Object> queue() { return task.queue; }
 147 
 148     /**
 149      * CleanerImpl.Task manages a set of object references and corresponding
 150      * cleaning actions and executes them after they are enqueued.
 151      */
 152     private static final class Task implements Runnable {
 153         /**
 154          * Heads of a CleanableList for each reference type.
 155          */


< prev index next >