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 Finaliz(ato|e)r(s).
  90      */
  91     static final class FinalizrHandler extends RecursiveAction {
  92         private Reference<?> finalzrs;
  93 
  94         FinalizrHandler(Reference<?> finalzrs) {
  95             this.finalzrs = finalzrs;
  96         }
  97 
  98         @Override
  99         protected void compute() {
 100             Reference<?> f = finalzrs;
 101             if (f != null) {
 102                 finalzrs = null;
 103                 for (Reference<?> n = f.next; ; f = n, n = f.next) {
 104                     f.next = f;
 105                     // Finalizer and Finalizator are both Runnable(s)
 106                     ((Runnable) f).run();
 107                     if (n == f) { // last in chunk
 108                         break;
 109                     }
 110                 }
 111             }
 112         }
 113 
 114         void submit() {
 115             if (Thread.currentThread() instanceof ForkJoinWorkerThread) {
 116                 // internal submission
 117                 fork();
 118             } else {
 119                 // external submission
 120                 pool.submit(this);
 121             }
 122         }
 123     }
 124 }
 125