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 }