1 package java.lang.ref;
   2 
   3 import java.util.concurrent.ForkJoinPool;
   4 import java.util.concurrent.ForkJoinWorkerThread;
   5 import java.util.concurrent.RecursiveAction;
   6 import java.util.concurrent.TimeUnit;
   7 
   8 /**
   9  * A holder for a ForkJoinPool and tasks executing Finalizer(s), Cleaner(s) and
  10  * enqueuing other Reference(s).
  11  */
  12 final class ReferenceHandling {
  13 
  14     private static final ForkJoinPool pool = createPool();
  15 
  16     /**
  17      * Starts handling of references. Called from {@code Reference.<clinit>}
  18      * after VM has booted.
  19      */
  20     static void start() {
  21         // triggers class initialization if not already initialized
  22         pool.getClass();
  23     }
  24 
  25     /**
  26      * Called from {@link Finalizer#runFinalization()} as part of forked secondary
  27      * finalizer thread to run all pending finalizers. We just help the ForkJoinPool
  28      * by waiting for it to quiesce.
  29      */
  30     static void runFinalization() {
  31         do {
  32         } while (!pool.awaitQuiescence(5, TimeUnit.SECONDS));
  33     }
  34 
  35     /**
  36      * Creates new ForkJoinPool for handling the references.
  37      */
  38     private static ForkJoinPool createPool() {
  39         String refHandlingThreadsString =
  40             System.getProperty("java.lang.ref.referenceHandlingThreads", "1");
  41         int referenceHandlingThreads;
  42         try {
  43             referenceHandlingThreads = Math.min(
  44                 Runtime.getRuntime().availableProcessors(),
  45                 Math.max(1, Integer.parseInt(refHandlingThreadsString))
  46             );
  47         } catch (NumberFormatException e) {
  48             referenceHandlingThreads = 1;
  49         }
  50         return new ForkJoinPool(
  51             referenceHandlingThreads,
  52             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
  53             null,
  54             true
  55         );
  56     }
  57 
  58     /**
  59      * A task that handles one chunk of references.
  60      */
  61     static final class PendingChunkHandler extends RecursiveAction {
  62         private Reference<?> chunk;
  63 
  64         PendingChunkHandler(Reference<?> chunk) {
  65             this.chunk = chunk;
  66         }
  67 
  68         @Override
  69         protected void compute() {
  70             Reference<?> r = this.chunk;
  71             if (r != null) {
  72                 this.chunk = null;
  73                 Reference.handlePendingChunk(r);
  74             }
  75         }
  76 
  77         void submit() {
  78             if (Thread.currentThread() instanceof ForkJoinWorkerThread) {
  79                 // internal submission
  80                 fork();
  81             } else {
  82                 // external submission
  83                 pool.submit(this);
  84             }
  85         }
  86     }
  87 
  88     /**
  89      * A task for handling a chunk of Finalizer(s).
  90      */
  91     static final class FinalizerHandler extends RecursiveAction {
  92         private Reference<?> finalizers;
  93 
  94         FinalizerHandler(Reference<?> finalizers) {
  95             this.finalizers = finalizers;
  96         }
  97 
  98         @Override
  99         protected void compute() {
 100             Reference<?> f = finalizers;
 101             if (f != null) {
 102                 finalizers = null;
 103                 for (Reference<?> n = f.next; ; f = n, n = f.next) {
 104                     f.next = f;
 105                     ((Finalizer) f).runFinalizer();
 106                     if (n == f) { // last in chunk
 107                         break;
 108                     }
 109                 }
 110             }
 111         }
 112 
 113         void submit() {
 114             if (Thread.currentThread() instanceof ForkJoinWorkerThread) {
 115                 // internal submission
 116                 fork();
 117             } else {
 118                 // external submission
 119                 pool.submit(this);
 120             }
 121         }
 122     }
 123 }
 124