1 /* 2 * Copyright (c) 2003, 2013, 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<Object> 61 { 62 63 // Doubly-linked list of live cleaners, which prevents the cleaners 64 // themselves from being GC'd before their referents 65 // 66 static private Cleaner first = null; 67 68 private Cleaner 69 next = null, 70 prev = null; 71 72 private static synchronized Cleaner add(Cleaner cl) { 73 if (first != null) { 74 cl.next = first; 75 first.prev = cl; 76 } 77 first = cl; 78 return cl; 79 } 80 81 private static synchronized boolean remove(Cleaner cl) { 82 83 // If already removed, do nothing 84 if (cl.next == cl) 85 return false; 86 87 // Update list 88 if (first == cl) { 89 if (cl.next != null) 90 first = cl.next; 91 else 92 first = cl.prev; 93 } 94 if (cl.next != null) 95 cl.next.prev = cl.prev; 96 if (cl.prev != null) 97 cl.prev.next = cl.next; 98 99 // Indicate removal by pointing the cleaner to itself 100 cl.next = cl; 101 cl.prev = cl; 102 return true; 103 104 } 105 106 private final Runnable thunk; 107 108 private Cleaner(Object referent, Runnable thunk) { 109 super(referent, null); 110 this.thunk = thunk; 111 } 112 113 /** 114 * Creates a new cleaner. 115 * 116 * @param ob the referent object to be cleaned 117 * @param thunk 118 * The cleanup code to be run when the cleaner is invoked. The 119 * cleanup code is run directly from the reference-handler thread, 120 * so it should be as simple and straightforward as possible. 121 * 122 * @return The new cleaner 123 */ 124 public static Cleaner create(Object ob, Runnable thunk) { 125 if (thunk == null) 126 return null; 127 return add(new Cleaner(ob, thunk)); 128 } 129 130 /** 131 * Runs this cleaner, if it has not been run before. 132 */ 133 public void clean() { 134 if (!remove(this)) 135 return; 136 try { 137 thunk.run(); 138 } catch (final Throwable x) { 139 AccessController.doPrivileged(new PrivilegedAction<>() { 140 public Void run() { 141 if (System.err != null) 142 new Error("Cleaner terminated abnormally", x) 143 .printStackTrace(); 144 System.exit(1); 145 return null; 146 }}); 147 } 148 } 149 150 }