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