1 /* 2 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.misc; 27 28 import java.lang.ref.*; 29 import java.security.AccessController; 30 import java.security.PrivilegedAction; 31 32 33 /** 34 * General-purpose phantom-reference-based cleaners. 35 * 36 * <p> Cleaners are a lightweight and more robust alternative to finalization. 37 * They are lightweight because they are not created by the VM and thus do not 38 * require a JNI upcall to be created, and because their cleanup code is 39 * invoked directly by the reference-handler thread rather than by the 40 * finalizer thread. They are more robust because they use phantom references, 41 * the weakest type of reference object, thereby avoiding the nasty ordering 42 * problems inherent to finalization. 43 * 44 * <p> A cleaner tracks a referent object and encapsulates a thunk of arbitrary 45 * cleanup code. Some time after the GC detects that a cleaner's referent has 46 * become phantom-reachable, the reference-handler thread will run the cleaner. 47 * Cleaners may also be invoked directly; they are thread safe and ensure that 48 * they run their thunks at most once. 49 * 50 * <p> Cleaners are not a replacement for finalization. They should be used 51 * only when the cleanup code is extremely simple and straightforward. 52 * Nontrivial cleaners are inadvisable since they risk blocking the 53 * reference-handler thread and delaying further cleanup and finalization. 54 * 55 * 56 * @author Mark Reinhold 57 */ 58 59 public class Cleaner 60 extends PhantomReference 61 { 62 63 // Dummy reference queue, needed because the PhantomReference constructor 64 // insists that we pass a queue. Nothing will ever be placed on this queue 65 // since the reference handler invokes cleaners explicitly. 66 // 67 private static final ReferenceQueue dummyQueue = new ReferenceQueue(); 68 69 // Doubly-linked list of live cleaners, which prevents the cleaners 70 // themselves from being GC'd before their referents 71 // 72 static private Cleaner first = null; 73 74 private Cleaner 75 next = null, 76 prev = null; 77 add(Cleaner cl)78 private static synchronized Cleaner add(Cleaner cl) { 79 if (first != null) { 80 cl.next = first; 81 first.prev = cl; 82 } 83 first = cl; 84 return cl; 85 } 86 remove(Cleaner cl)87 private static synchronized boolean remove(Cleaner cl) { 88 89 // If already removed, do nothing 90 if (cl.next == cl) 91 return false; 92 93 // Update list 94 if (first == cl) { 95 if (cl.next != null) 96 first = cl.next; 97 else 98 first = cl.prev; 99 } 100 if (cl.next != null) 101 cl.next.prev = cl.prev; 102 if (cl.prev != null) 103 cl.prev.next = cl.next; 104 105 // Indicate removal by pointing the cleaner to itself 106 cl.next = cl; 107 cl.prev = cl; 108 return true; 109 110 } 111 112 private final Runnable thunk; 113 Cleaner(Object referent, Runnable thunk)114 private Cleaner(Object referent, Runnable thunk) { 115 super(referent, dummyQueue); 116 this.thunk = thunk; 117 } 118 119 /** 120 * Creates a new cleaner. 121 * 122 * @param thunk 123 * The cleanup code to be run when the cleaner is invoked. The 124 * cleanup code is run directly from the reference-handler thread, 125 * so it should be as simple and straightforward as possible. 126 * 127 * @return The new cleaner 128 */ create(Object ob, Runnable thunk)129 public static Cleaner create(Object ob, Runnable thunk) { 130 if (thunk == null) 131 return null; 132 return add(new Cleaner(ob, thunk)); 133 } 134 135 /** 136 * Runs this cleaner, if it has not been run before. 137 */ clean()138 public void clean() { 139 if (!remove(this)) 140 return; 141 try { 142 thunk.run(); 143 } catch (final Throwable x) { 144 AccessController.doPrivileged(new PrivilegedAction<Void>() { 145 public Void run() { 146 if (System.err != null) 147 new Error("Cleaner terminated abnormally", x) 148 .printStackTrace(); 149 System.exit(1); 150 return null; 151 }}); 152 } 153 } 154 155 } 156