1 /* 2 * Copyright (c) 2015, 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 java.lang.ref; 27 28 import sun.misc.InnocuousThread; 29 import sun.misc.ManagedLocalsThread; 30 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.Objects; 34 import java.util.concurrent.ThreadFactory; 35 36 /** 37 * Cleaner manages a set of object references and corresponding cleanup functions. 38 * Each Cleaner operates independently, managing the pending cleanup functions 39 * and handling threading and termination when the Cleaner is no longer in use. 40 * Registering an object reference and corresponding cleaning function returns 41 * allows the cleaning function to be invoked explicitly 42 * {@link Cleanable#clean invoked} or to be 43 * {@link Cleanable#clear cleared}. 44 * The most efficient use is to explicitly invoke the 45 * {@link Cleanable#clean Cleanable.clean} method when the object 46 * is closed or no longer needed. 47 * The cleaning function is invoked at most once when the object is 48 * no longer reachable unless it has already been explicitly cleaned or cleared. 49 * Note that the cleaning function must not refer to the object being registered. 50 * If so, the object will not become unreachable and the cleaning function 51 * will not be invoked. 52 * <p> 53 * Cleaning functions are registered as: 54 * <ul> 55 * <li>{@link #phantomCleanable(Object object, Runnable thunk) phantomCleanable} 56 * registers the Runnable to be run when the object becomes phantom reachable. 57 * <li>{@link #weakCleanable(Object object, Runnable thunk) weakCleanable} 58 * registers the Runnable to be run when object becomes weakly reachable. 59 * <li>{@link #softCleanable(Object object, Runnable thunk) softCleanable} 60 * registers the Runnable to be run when object becomes softly reachable. 61 * </ul> 62 * <p> 63 * The execution of the cleaning function is performed 64 * by a thread associated with the Cleaner. 65 * The thread runs until all registered cleaning functions have 66 * executed and the Cleaner itself is reclaimed by the garbage collector. 67 * Cleaning functions should be prepared to be executed concurrently with 68 * other cleaning functions. 69 * <p> 70 * The behavior of the Cleaner during {@link System#exit(int) System.exit} 71 * is implementation specific. No guarantees are made related 72 * to whether cleaning functions are executed or not. 73 * 74 * @author Roger Riggs 75 * @author Kim Barrett 76 * @apiNote Typically the cleaning functions should be very quick to execute 77 * and not block. If the cleaning function blocks it may delay processing 78 * other cleaning functions using the same Cleaner. It is up to the application 79 * to have mutually compatible cleaning functions on a Cleaner. 80 */ 81 public final class Cleaner { 82 83 /** 84 * The Cleaner implementation. 85 */ 86 final CleanerImpl impl; 87 88 /** 89 * Construct a Cleaner implementation and start it. 90 */ 91 private Cleaner() { 92 impl = new CleanerImpl(); 93 } 94 95 /** 96 * Return a new Cleaner. 97 * <p> 98 * The Cleaner creates a daemon thread to process the 99 * unreachable objects and to invoke cleaning functions. 100 * <p> 101 * The Cleaner terminates when it is unreachable and all of the objects 102 * registered are unreachable and corresponding Runnables are complete. 103 * 104 * @return a new Cleaner 105 */ 106 public static Cleaner create() { 107 return create(InnocuousThreadFactory.factory()); 108 } 109 110 /** 111 * Returns a new Cleaner using a ThreadFactory. 112 * The cleaning functions are processed on a new Thread from the {@link ThreadFactory}. 113 * The Thread is {@link Thread#start started} to process cleaning functions. 114 * The factory should set the Thread attributes as needed for 115 * priority, name, thread group, uncaught exception handler, etc. 116 * The thread is set to be a {@link Thread#setDaemon(boolean) daemon thread}. 117 * The Cleaner uses this daemon thread to process the 118 * unreachable objects and to invoke cleaning functions. 119 * <p> 120 * The Cleaner terminates when it is unreachable and all of the objects 121 * registered are unreachable and corresponding Runnables are complete. 122 * 123 * @param threadFactory a Thread factory to return a new Thread to 124 * process cleaning functions 125 * @return a new Cleaner 126 */ 127 public static Cleaner create(ThreadFactory threadFactory) { 128 Cleaner cleaner = new Cleaner(); 129 cleaner.impl.start(cleaner, threadFactory); 130 return cleaner; 131 } 132 133 /** 134 * Registers an object and a Runnable to be run when the object 135 * becomes phantom reachable. 136 * Refer to the class javadoc for cautions about the behavior 137 * of cleaning functions. 138 * 139 * @param obj the object to monitor 140 * @param thunk a Runnable to invoke when the object becomes phantom reachable 141 * @return a Cleanable instance 142 */ 143 public Cleanable phantomCleanable(Object obj, Runnable thunk) { 144 Objects.requireNonNull(obj, "obj"); 145 Objects.requireNonNull(thunk, "thunk"); 146 return new PhantomCleanableRef(obj, this, thunk); 147 } 148 149 /** 150 * Registers an object and a Runnable to be run when the object 151 * becomes weakly reachable. 152 * Refer to the class javadoc for cautions about the behavior 153 * of cleaning functions. 154 * 155 * @param obj the object to monitor 156 * @param thunk a Runnable to invoke when the object becomes weakly reachable 157 * @return a Cleanable instance 158 */ 159 public Cleanable weakCleanable(Object obj, Runnable thunk) { 160 Objects.requireNonNull(obj, "obj"); 161 Objects.requireNonNull(thunk, "thunk"); 162 return new WeakCleanableRef(obj, this, thunk); 163 } 164 165 /** 166 * Registers an object and a Runnable to be run when the object 167 * becomes softly reachable. 168 * Refer to the class javadoc for cautions about the behavior 169 * of cleaning functions. 170 * 171 * @param obj the object to monitorss 172 * @param thunk a Runnable to invoke when the object becomes softly reachable 173 * @return a Cleanable instance 174 */ 175 public Cleanable softCleanable(Object obj, Runnable thunk) { 176 Objects.requireNonNull(obj, "obj"); 177 Objects.requireNonNull(thunk, "thunk"); 178 return new SoftCleanableRef(obj, this, thunk); 179 } 180 181 /** 182 * CleanerImpl manages the thread and the pending cleanup functions. 183 */ 184 static final class CleanerImpl implements Runnable { 185 // Head of the Cleanable list 186 private final CleanableList cleanableList; 187 188 // The queue of pending cleaning functions 189 final ReferenceQueue<Object> queue; 190 191 // The lock used to insert or remove a cleaning function from the cleanableList. 192 private final Object lock; 193 194 // Construct a CleanerImpl. 195 CleanerImpl() { 196 queue = new ReferenceQueue<>(); 197 lock = new Object(); 198 cleanableList = new CleanableList(); 199 } 200 201 /** 202 * Starts the Cleaner implementation. 203 * When started waits for Cleanables to be queued. 204 */ 205 void start(Cleaner service, ThreadFactory threadFactory) { 206 // schedule a nop cleaning function for the service, so the associated thread 207 // will continue to run at least until the service is reclaimable. 208 new PhantomCleanableReference<Cleaner>(service, service) { 209 @Override protected void performCleanup() { } 210 }; 211 212 // now that there's at least one cleaning function, for the service, 213 // we can start the associated thread, which runs until 214 // all cleaning functions have been run. 215 Thread thread = threadFactory.newThread(this); 216 thread.setPriority(Thread.MAX_PRIORITY); 217 thread.setDaemon(true); 218 thread.start(); 219 } 220 221 /** 222 * Insert given Cleanable after the cleanableList head. 223 * 224 * @param c the Cleanable to insert after cleanableList head 225 */ 226 void insert(Cleanable c) { 227 synchronized (lock) { 228 setPrev(c, cleanableList); 229 Cleanable clNext = getNext(cleanableList); 230 setNext(c, clNext); 231 setPrev(clNext, c); 232 setNext(cleanableList, c); 233 } 234 } 235 236 /** 237 * Remove given Cleanable from the cleanableList. 238 * 239 * @param c the Cleanable to remove from the cleanableList 240 * @return true if Cleanable was removed or false if not because 241 * it had already been removed before 242 */ 243 boolean remove(Cleanable c) { 244 synchronized (lock) { 245 if (getNext(c) != c) { 246 setPrev(getNext(c), getPrev(c)); 247 setNext(getPrev(c), getNext(c)); 248 setPrev(c, c); 249 setNext(c, c); 250 return true; 251 } 252 return false; 253 } 254 } 255 256 // "polymorphic" next/prev field accessors... 257 // (wish there were package-private interface methods) 258 259 private Cleanable getNext(Cleanable c) { 260 if (c instanceof WeakCleanableReference) { 261 return ((WeakCleanableReference<?>)c).next; 262 } else if (c instanceof SoftCleanableReference) { 263 return ((SoftCleanableReference<?>)c).next; 264 } else if (c instanceof PhantomCleanableReference) { 265 return ((PhantomCleanableReference<?>)c).next; 266 } else if (c instanceof CleanableList) { 267 return ((CleanableList)c).next; 268 } else { 269 throw invalidCleanable(c); 270 } 271 } 272 273 private void setNext(Cleanable c, Cleanable next) { 274 if (c instanceof WeakCleanableReference) { 275 ((WeakCleanableReference<?>)c).next = next; 276 } else if (c instanceof SoftCleanableReference) { 277 ((SoftCleanableReference<?>)c).next = next; 278 } else if (c instanceof PhantomCleanableReference) { 279 ((PhantomCleanableReference<?>)c).next = next; 280 } else if (c instanceof CleanableList) { 281 ((CleanableList)c).next = next; 282 } else { 283 throw invalidCleanable(c); 284 } 285 } 286 287 private Cleanable getPrev(Cleanable c) { 288 if (c instanceof WeakCleanableReference) { 289 return ((WeakCleanableReference<?>)c).prev; 290 } else if (c instanceof SoftCleanableReference) { 291 return ((SoftCleanableReference<?>)c).prev; 292 } else if (c instanceof PhantomCleanableReference) { 293 return ((PhantomCleanableReference<?>)c).prev; 294 } else if (c instanceof CleanableList) { 295 return ((CleanableList)c).prev; 296 } else { 297 throw invalidCleanable(c); 298 } 299 } 300 301 private void setPrev(Cleanable c, Cleanable prev) { 302 if (c instanceof WeakCleanableReference) { 303 ((WeakCleanableReference<?>)c).prev = prev; 304 } else if (c instanceof SoftCleanableReference) { 305 ((SoftCleanableReference<?>)c).prev = prev; 306 } else if (c instanceof PhantomCleanableReference) { 307 ((PhantomCleanableReference<?>)c).prev = prev; 308 } else if (c instanceof CleanableList) { 309 ((CleanableList)c).prev = prev; 310 } else { 311 throw invalidCleanable(c); 312 } 313 } 314 315 private static Error invalidCleanable(Cleanable c) { 316 return new InternalError("Invalid Cleanable class: " + 317 c.getClass().getName()); 318 } 319 320 /** 321 * Process queued Cleanables as long as the cleanableList is not empty. 322 * A Cleanable is in the list for each Object and for the Cleaner 323 * itself. 324 * Terminates when the Cleaner is no longer reachable and 325 * has been cleaned and there are no more Cleanable instances 326 * for which the object is reachable. 327 * <p> 328 * If the thread is a ManagedLocalsThread, the threadlocals 329 * are erased before each cleanup 330 */ 331 public void run() { 332 Thread t = Thread.currentThread(); 333 ManagedLocalsThread mlThread = (t instanceof ManagedLocalsThread) 334 ? (ManagedLocalsThread)t 335 : null; 336 while (!cleanableList.isEmpty()) { 337 if (mlThread != null) { 338 // Cleanable the thread locals 339 mlThread.eraseThreadLocals(); 340 } 341 try { 342 Cleanable ref = (Cleanable) queue.remove(); 343 ref.clean(); 344 } catch (InterruptedException i) { 345 continue; // ignore the interruption 346 } catch (RuntimeException e) { 347 // ignore exceptions from the cleanup thunk 348 } 349 } 350 } 351 } 352 353 /** 354 * Cleanable instances allow a registered cleaning function to be cleaned or cleared. 355 * Cleanable Runnables are invoked at most once. 356 */ 357 public interface Cleanable { 358 /** 359 * Unregisters the Cleanable. 360 * Due to inherent concurrency, the cleaning function may still be invoked. 361 */ 362 void clear(); 363 364 /** 365 * Unregister the Cleanable and invoke the Runnable, 366 * ensuring at-most-once semantics. 367 */ 368 void clean(); 369 } 370 371 /** 372 * Perform cleaning on an unreachable PhantomReference. 373 */ 374 static final class PhantomCleanableRef extends PhantomCleanableReference<Object> { 375 private final Runnable thunk; 376 377 PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable thunk) { 378 super(obj, cleaner); 379 this.thunk = thunk; 380 } 381 382 @Override 383 protected void performCleanup() { 384 thunk.run(); 385 } 386 387 /** 388 * Prevent access to referent even when it is still alive. 389 * @throws UnsupportedOperationException always 390 * @return nothing 391 */ 392 @Override 393 public Object get() { 394 throw new UnsupportedOperationException(); 395 } 396 } 397 398 /** 399 * Perform cleaning on an unreachable WeakReference. 400 */ 401 static final class WeakCleanableRef extends WeakCleanableReference<Object> { 402 private final Runnable thunk; 403 404 WeakCleanableRef(Object obj, Cleaner cleaner, Runnable thunk) { 405 super(obj, cleaner); 406 this.thunk = thunk; 407 } 408 409 @Override 410 protected void performCleanup() { 411 thunk.run(); 412 } 413 414 /** 415 * Prevent access to referent even when it is still alive. 416 * @throws UnsupportedOperationException always 417 * @return nothing 418 */ 419 @Override 420 public Object get() { 421 throw new UnsupportedOperationException(); 422 } 423 } 424 425 /** 426 * Perform cleaning on an unreachable SoftReference. 427 */ 428 static final class SoftCleanableRef extends SoftCleanableReference<Object> { 429 private final Runnable thunk; 430 431 SoftCleanableRef(Object obj, Cleaner cleaner, Runnable thunk) { 432 super(obj, cleaner); 433 this.thunk = thunk; 434 } 435 436 @Override 437 protected void performCleanup() { 438 thunk.run(); 439 } 440 441 /** 442 * Prevent access to referent even when it is still alive. 443 * @throws UnsupportedOperationException always 444 * @return nothing 445 */ 446 @Override 447 public Object get() { 448 throw new UnsupportedOperationException(); 449 } 450 } 451 452 static final class CleanableList implements Cleanable { 453 454 Cleanable prev = this, next = this; 455 456 boolean isEmpty() { 457 return next == this; 458 } 459 460 @Override 461 public void clear() { 462 throw new UnsupportedOperationException(); 463 } 464 465 @Override 466 public void clean() { 467 throw new UnsupportedOperationException(); 468 } 469 } 470 471 /** 472 * A ThreadFactory for InnocuousThreads (the default). 473 * The factory is a singleton. 474 */ 475 static class InnocuousThreadFactory implements ThreadFactory { 476 final static ThreadFactory factory = new InnocuousThreadFactory(); 477 static ThreadFactory factory() { 478 return factory; 479 } 480 public Thread newThread(Runnable r) { 481 return AccessController.doPrivileged((PrivilegedAction<Thread>) () -> { 482 Thread t = new InnocuousThread(r); 483 t.setName("Cleaner-" + t.getId()); 484 return t; 485 }); 486 } 487 } 488 }