1 /* 2 * Copyright (c) 2015, 2016, 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 jdk.internal.ref; 27 28 import jdk.internal.misc.InnocuousThread; 29 30 import java.lang.ref.Cleaner; 31 import java.lang.ref.ReferenceQueue; 32 import java.security.AccessController; 33 import java.security.PrivilegedAction; 34 import java.util.Objects; 35 import java.util.concurrent.ThreadFactory; 36 import java.util.concurrent.atomic.AtomicInteger; 37 38 /** 39 * CleanerImpl is the implementation of {@link Cleaner}. 40 */ 41 public class CleanerImpl implements Cleaner { 42 43 final Task task; 44 45 public CleanerImpl(ThreadFactory threadFactory) { 46 task = new Task(); 47 task.start(this, threadFactory); 48 } 49 50 @Override 51 public Cleanable register(Object obj, Runnable action) { 52 Objects.requireNonNull(obj, "obj"); 53 Objects.requireNonNull(action, "action"); 54 return new CleanerImpl.PhantomCleanableRef(obj, this, action); 55 } 56 57 // package-private access to Task's state 58 PhantomCleanable<?> phantomCleanableList() { return task.phantomCleanableList; } 59 WeakCleanable<?> weakCleanableList() { return task.weakCleanableList; } 60 SoftCleanable<?> softCleanableList() { return task.softCleanableList; } 61 ReferenceQueue<Object> queue() { return task.queue; } 62 63 /** 64 * CleanerImpl.Task manages a set of object references and corresponding 65 * cleaning actions and executes them after they are enqueued. 66 */ 67 private static final class Task implements Runnable { 68 /** 69 * Heads of a CleanableList for each reference type. 70 */ 71 final PhantomCleanable<?> phantomCleanableList; 72 73 final WeakCleanable<?> weakCleanableList; 74 75 final SoftCleanable<?> softCleanableList; 76 77 // The ReferenceQueue of pending cleaning actions 78 final ReferenceQueue<Object> queue; 79 80 /** 81 * Constructor for Task. 82 */ 83 Task() { 84 queue = new ReferenceQueue<>(); 85 phantomCleanableList = new PhantomCleanableRef(); 86 weakCleanableList = new WeakCleanableRef(); 87 softCleanableList = new SoftCleanableRef(); 88 } 89 90 /** 91 * Starts the Cleaner implementation. 92 * Ensure this is the CleanerImpl for the Cleaner. 93 * When started waits for Cleanables to be queued. 94 * @param cleaner the cleaner 95 * @param threadFactory the thread factory 96 */ 97 void start(CleanerImpl cleaner, ThreadFactory threadFactory) { 98 if (cleaner.task != this) { 99 throw new AssertionError("wrong cleaner"); 100 } 101 // schedule a nop cleaning action for the cleaner, so the associated thread 102 // will continue to run at least until the cleaner is reclaimable. 103 new CleanerCleanable(cleaner); 104 105 if (threadFactory == null) { 106 threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); 107 } 108 109 // now that there's at least one cleaning action, for the cleaner, 110 // we can start the associated thread, which runs until 111 // all cleaning actions have been run. 112 Thread thread = threadFactory.newThread(this); 113 thread.setDaemon(true); 114 thread.start(); 115 } 116 117 /** 118 * Process queued Cleanables as long as the cleanable lists are not empty. 119 * A Cleanable is in one of the lists for each Object and for the Cleaner 120 * itself. 121 * Terminates when the Cleaner is no longer reachable and 122 * has been cleaned and there are no more Cleanable instances 123 * for which the object is reachable. 124 * <p> 125 * If the thread is a ManagedLocalsThread, the threadlocals 126 * are erased before each cleanup 127 */ 128 @Override 129 public void run() { 130 Thread t = Thread.currentThread(); 131 InnocuousThread mlThread = (t instanceof InnocuousThread) 132 ? (InnocuousThread) t 133 : null; 134 while (!phantomCleanableList.isListEmpty() || 135 !weakCleanableList.isListEmpty() || 136 !softCleanableList.isListEmpty()) { 137 if (mlThread != null) { 138 // Clear the thread locals 139 mlThread.eraseThreadLocals(); 140 } 141 try { 142 // Wait for a Ref, with a timeout to avoid getting hung 143 // due to a race with clear/clean 144 Cleanable ref = (Cleanable) queue.remove(60 * 1000L); 145 if (ref != null) { 146 ref.clean(); 147 } 148 } catch (Throwable e) { 149 // ignore exceptions from the cleanup action 150 // (including interruption of cleanup thread) 151 } 152 } 153 } 154 } 155 156 /** 157 * Perform cleaning on an unreachable PhantomReference. 158 */ 159 public static final class PhantomCleanableRef extends PhantomCleanable<Object> { 160 private final Runnable action; 161 162 /** 163 * Constructor for a phantom cleanable reference. 164 * @param obj the object to monitor 165 * @param cleaner the cleaner 166 * @param action the action Runnable 167 */ 168 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) { 169 super(obj, cleaner); 170 this.action = action; 171 } 172 173 /** 174 * Constructor used only for root of phantom cleanable list. 175 */ 176 PhantomCleanableRef() { 177 super(); 178 this.action = null; 179 } 180 181 @Override 182 protected void performCleanup() { 183 action.run(); 184 } 185 186 /** 187 * Prevent access to referent even when it is still alive. 188 * 189 * @throws UnsupportedOperationException always 190 */ 191 @Override 192 public Object get() { 193 throw new UnsupportedOperationException("get"); 194 } 195 196 /** 197 * Direct clearing of the referent is not supported. 198 * 199 * @throws UnsupportedOperationException always 200 */ 201 @Override 202 public void clear() { 203 throw new UnsupportedOperationException("clear"); 204 } 205 } 206 207 /** 208 * Perform cleaning on an unreachable WeakReference. 209 */ 210 public static final class WeakCleanableRef extends WeakCleanable<Object> { 211 private final Runnable action; 212 213 /** 214 * Constructor for a weak cleanable reference. 215 * @param obj the object to monitor 216 * @param cleaner the cleaner 217 * @param action the action Runnable 218 */ 219 WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) { 220 super(obj, cleaner); 221 this.action = action; 222 } 223 224 /** 225 * Constructor used only for root of weak cleanable list. 226 */ 227 WeakCleanableRef() { 228 super(); 229 this.action = null; 230 } 231 232 @Override 233 protected void performCleanup() { 234 action.run(); 235 } 236 237 /** 238 * Prevent access to referent even when it is still alive. 239 * 240 * @throws UnsupportedOperationException always 241 */ 242 @Override 243 public Object get() { 244 throw new UnsupportedOperationException("get"); 245 } 246 247 /** 248 * Direct clearing of the referent is not supported. 249 * 250 * @throws UnsupportedOperationException always 251 */ 252 @Override 253 public void clear() { 254 throw new UnsupportedOperationException("clear"); 255 } 256 } 257 258 /** 259 * Perform cleaning on an unreachable SoftReference. 260 */ 261 public static final class SoftCleanableRef extends SoftCleanable<Object> { 262 private final Runnable action; 263 264 /** 265 * Constructor for a soft cleanable reference. 266 * @param obj the object to monitor 267 * @param cleaner the cleaner 268 * @param action the action Runnable 269 */ 270 SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) { 271 super(obj, cleaner); 272 this.action = action; 273 } 274 275 /** 276 * Constructor used only for root of soft cleanable list. 277 */ 278 SoftCleanableRef() { 279 super(); 280 this.action = null; 281 } 282 283 @Override 284 protected void performCleanup() { 285 action.run(); 286 } 287 288 /** 289 * Prevent access to referent even when it is still alive. 290 * 291 * @throws UnsupportedOperationException always 292 */ 293 @Override 294 public Object get() { 295 throw new UnsupportedOperationException("get"); 296 } 297 298 /** 299 * Direct clearing of the referent is not supported. 300 * 301 * @throws UnsupportedOperationException always 302 */ 303 @Override 304 public void clear() { 305 throw new UnsupportedOperationException("clear"); 306 } 307 308 } 309 310 /** 311 * A ThreadFactory for InnocuousThreads. 312 * The factory is a singleton. 313 */ 314 static final class InnocuousThreadFactory implements ThreadFactory { 315 final static ThreadFactory factory = new InnocuousThreadFactory(); 316 317 static ThreadFactory factory() { 318 return factory; 319 } 320 321 final AtomicInteger cleanerThreadNumber = new AtomicInteger(); 322 323 public Thread newThread(Runnable r) { 324 return AccessController.doPrivileged(new PrivilegedAction<>() { 325 @Override 326 public Thread run() { 327 Thread t = InnocuousThread.newThread(r); 328 t.setPriority(Thread.MAX_PRIORITY - 2); 329 t.setName("Cleaner-" + cleanerThreadNumber.getAndIncrement()); 330 return t; 331 } 332 }); 333 } 334 } 335 336 /** 337 * A PhantomCleanable implementation for tracking the Cleaner itself. 338 */ 339 static final class CleanerCleanable extends PhantomCleanable<Cleaner> { 340 CleanerCleanable(Cleaner cleaner) { 341 super(cleaner, cleaner); 342 } 343 344 @Override 345 protected void performCleanup() { 346 // no action 347 } 348 } 349 }