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 for handling pending and
  10  * Cleaner references.
  11  */
  12 final class ReferenceHandling {
  13 
  14     private static final ForkJoinPool pool = createPool();
  15 
  16     /**
  17      * Called from {@link Finalizer#runFinalization()} as part of forked secondary
  18      * finalizer thread to run all pending AutoRunnable(s). We just help the ForkJoinPool
  19      * by lending current thread while waiting for pool to quiesce.
  20      */
  21     static void runFinalization() {
  22         do {
  23         } while (!pool.awaitQuiescence(5, TimeUnit.SECONDS));
  24     }
  25 
  26     /**
  27      * Creates new ForkJoinPool for handling the references.
  28      */
  29     private static ForkJoinPool createPool() {
  30         String refHandlingThreadsString =
  31             System.getProperty("java.lang.ref.referenceHandlingThreads", "1");
  32         int referenceHandlingThreads;
  33         try {
  34             referenceHandlingThreads = Math.min(
  35                 Runtime.getRuntime().availableProcessors(),
  36                 Math.max(1, Integer.parseInt(refHandlingThreadsString))
  37                                                );
  38         } catch (NumberFormatException e) {
  39             referenceHandlingThreads = 1;
  40         }
  41         return new ForkJoinPool(
  42             referenceHandlingThreads,
  43             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
  44             null,
  45             true
  46         );
  47     }
  48 
  49     /**
  50      * A task that handles one chunk of references. A chunk
  51      * is linked using 'discovered' links. Last in chunk is linked to 'null'.
  52      */
  53     static final class PendingChunkHandler extends RecursiveAction {
  54         private static final long serialVersionUID = 1L;
  55 
  56         private Reference<?> chunk;
  57 
  58         PendingChunkHandler(Reference<?> chunk) {
  59             this.chunk = chunk;
  60         }
  61 
  62         @Override
  63         protected void compute() {
  64             Reference<?> r = this.chunk;
  65             if (r != null) {
  66                 this.chunk = null;
  67                 Reference.handlePendingChunk(r);
  68             }
  69         }
  70 
  71         void submit() {
  72             if (Thread.currentThread() instanceof ForkJoinWorkerThread) {
  73                 // internal submission
  74                 fork();
  75             } else {
  76                 // external submission
  77                 pool.submit(this);
  78             }
  79         }
  80     }
  81 
  82     /**
  83      * A task for handling a chunk of j.l.r.Cleaner Reference(s). A chunk
  84      * is linked using 'discovered' links. Last in chunk is linked to null.
  85      */
  86     static final class CleanersHandler extends RecursiveAction {
  87         private static final long serialVersionUID = 1L;
  88 
  89         private Reference<?> cleaners;
  90 
  91         CleanersHandler(Reference<?> cleaners) {
  92             this.cleaners = cleaners;
  93         }
  94 
  95         @Override
  96         protected void compute() {
  97             Reference<?> c = cleaners;
  98             if (c != null) {
  99                 cleaners = null;
 100                 Reference.handleCleaners(c);
 101             }
 102         }
 103 
 104         void submit() {
 105             if (Thread.currentThread() instanceof ForkJoinWorkerThread) {
 106                 // internal submission
 107                 fork();
 108             } else {
 109                 // external submission
 110                 pool.submit(this);
 111             }
 112         }
 113     }
 114 }