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 once from {@code Reference.<clinit>}
  18      * after VM has booted.
  19      */
  20     static void start() {
  21         pool.execute(new PendingChunkPoller());
  22     }
  23 
  24     /**
  25      * Called from {@link Finalizer#runFinalization()} as part of forked secondary
  26      * finalizer thread to run all pending finalizers. We just help the ForkJoinPool
  27      * by waiting for it to quiesce.
  28      */
  29     static void runFinalization() {
  30         do {} while (!pool.awaitQuiescence(5, TimeUnit.SECONDS));
  31     }
  32 
  33     /**
  34      * Creates new ForkJoinPool for handling the references.
  35      */
  36     private static ForkJoinPool createPool() {
  37         return new ForkJoinPool(
  38             Runtime.getRuntime().availableProcessors(),
  39             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
  40             null,
  41             true
  42         );
  43     }
  44 
  45     /**
  46      * An eternal task submitted once during initialization.
  47      * Polls for pending references and dispatches handling tasks.
  48      */
  49     private static final class PendingChunkPoller extends RecursiveAction {
  50         @Override
  51         protected void compute() {
  52             boolean[] morePending = new boolean[1];
  53             // this is an eternal task - never ends
  54             while (true) {
  55                 Reference<?> chunk = Reference.pollPendingChunk(true, morePending);
  56                 if (chunk != null) {
  57                     if (morePending[0]) {
  58                         // fork a handling task and return for more
  59                         new PendingChunkHandler(chunk).fork();
  60                     } else {
  61                         // no more pending, so we can handle the chunk directly
  62                         Reference.handlePendingChunk(chunk);
  63                     }
  64                 }
  65             }
  66         }
  67     }
  68 
  69     /**
  70      * A task that handles one chunk of references.
  71      */
  72     private static final class PendingChunkHandler extends RecursiveAction {
  73         private Reference<?> chunk;
  74 
  75         PendingChunkHandler(Reference<?> chunk) {
  76             this.chunk = chunk;
  77         }
  78 
  79         @Override
  80         protected void compute() {
  81             Reference<?> r = this.chunk;
  82             if (r != null) {
  83                 this.chunk = null;
  84                 Reference.handlePendingChunk(r);
  85             }
  86         }
  87     }
  88 
  89     /**
  90      * A task for handling a single Finalizer.
  91      */
  92     static final class FinalizerHandler extends RecursiveAction {
  93         private Finalizer finalizer;
  94 
  95         FinalizerHandler(Finalizer finalizer) {
  96             this.finalizer = finalizer;
  97         }
  98 
  99         @Override
 100         protected void compute() {
 101             Finalizer finalizer = this.finalizer;
 102             if (finalizer != null) {
 103                 this.finalizer = null;
 104                 finalizer.runFinalizer();
 105             }
 106         }
 107 
 108         void submit() {
 109             if (Thread.currentThread() instanceof ForkJoinWorkerThread) {
 110                 // internal submission
 111                 fork();
 112             } else {
 113                 // external submission
 114                 pool.submit(this);
 115             }
 116         }
 117     }
 118 }
 119