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 java.lang.ref.Cleaner;
29 import java.lang.ref.Cleaner.Cleanable;
30 import java.lang.ref.ReferenceQueue;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.concurrent.ThreadFactory;
34 import java.util.function.Function;
35
36 import jdk.internal.misc.InnocuousThread;
37
38 /**
39 * CleanerImpl manages a set of object references and corresponding cleaning actions.
40 * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
41 */
42 public final class CleanerImpl {
43
44 /**
45 * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
46 */
47 private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
48
49 /**
50 * Heads of a CleanableList for each reference type.
51 */
52 final PhantomCleanable<?> phantomCleanableList;
53
54 final WeakCleanable<?> weakCleanableList;
55
56 final SoftCleanable<?> softCleanableList;
57
58 // The ReferenceQueue of pending cleaning actions
59 final ReferenceQueue<Object> queue;
60
61 /**
62 * Called by Cleaner static initialization to provide the function
86 public CleanerImpl() {
87 queue = new ReferenceQueue<>();
88 phantomCleanableList = new PhantomCleanableRef();
89 weakCleanableList = new WeakCleanableRef();
90 softCleanableList = new SoftCleanableRef();
91 }
92
93 /**
94 * Starts the Cleaner implementation.
95 * Ensure this is the CleanerImpl for the Cleaner.
96 * When started waits for Cleanables to be queued.
97 * @param cleaner the cleaner
98 * @param threadFactory the thread factory
99 */
100 public void start(Cleaner cleaner, ThreadFactory threadFactory) {
101 if (getCleanerImpl(cleaner) != this) {
102 throw new AssertionError("wrong cleaner");
103 }
104 // schedule a nop cleaning action for the cleaner, so the associated thread
105 // will continue to run at least until the cleaner is reclaimable.
106 new PhantomCleanableRef(cleaner, cleaner, () -> {});
107
108 if (threadFactory == null) {
109 threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
110 }
111
112 // now that there's at least one cleaning action, for the cleaner,
113 // we can start the associated thread, which runs until
114 // all cleaning actions have been run.
115 Thread thread = threadFactory.newThread(this::run);
116 thread.setDaemon(true);
117 thread.start();
118 }
119
120 /**
121 * Process queued Cleanables as long as the cleanable lists are not empty.
122 * A Cleanable is in one of the lists for each Object and for the Cleaner
123 * itself.
124 * Terminates when the Cleaner is no longer reachable and
125 * has been cleaned and there are no more Cleanable instances
126 * for which the object is reachable.
127 * <p>
128 * If the thread is a ManagedLocalsThread, the threadlocals
129 * are erased before each cleanup
130 */
131 private void run() {
132 Thread t = Thread.currentThread();
133 InnocuousThread mlThread = (t instanceof InnocuousThread)
134 ? (InnocuousThread) t
135 : null;
136 while (!phantomCleanableList.isListEmpty() ||
137 !weakCleanableList.isListEmpty() ||
138 !softCleanableList.isListEmpty()) {
139 if (mlThread != null) {
140 // Clear the thread locals
141 mlThread.eraseThreadLocals();
142 }
143 try {
144 // Wait for a Ref, with a timeout to avoid getting hung
145 // due to a race with clear/clean
146 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
147 if (ref != null) {
148 ref.clean();
149 }
150 } catch (InterruptedException i) {
151 continue; // ignore the interruption
152 } catch (Throwable e) {
153 // ignore exceptions from the cleanup action
154 }
155 }
156 }
157
158 /**
159 * Perform cleaning on an unreachable PhantomReference.
160 */
161 public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
162 private final Runnable action;
163
164 /**
165 * Constructor for a phantom cleanable reference.
166 * @param obj the object to monitor
167 * @param cleaner the cleaner
168 * @param action the action Runnable
169 */
170 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
171 super(obj, cleaner);
172 this.action = action;
173 }
303 * @throws UnsupportedOperationException always
304 */
305 @Override
306 public void clear() {
307 throw new UnsupportedOperationException("clear");
308 }
309
310 }
311
312 /**
313 * A ThreadFactory for InnocuousThreads.
314 * The factory is a singleton.
315 */
316 static final class InnocuousThreadFactory implements ThreadFactory {
317 final static ThreadFactory factory = new InnocuousThreadFactory();
318
319 static ThreadFactory factory() {
320 return factory;
321 }
322
323 public Thread newThread(Runnable r) {
324 return AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
325 Thread t = new InnocuousThread(r);
326 t.setPriority(Thread.MAX_PRIORITY - 2);
327 t.setName("Cleaner-" + t.getId());
328 return t;
329 });
330 }
331 }
332
333 }
|
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 java.lang.ref.Cleaner;
29 import java.lang.ref.Cleaner.Cleanable;
30 import java.lang.ref.ReferenceQueue;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.concurrent.ThreadFactory;
34 import java.util.concurrent.atomic.AtomicInteger;
35 import java.util.function.Function;
36
37 import jdk.internal.misc.InnocuousThread;
38
39 /**
40 * CleanerImpl manages a set of object references and corresponding cleaning actions.
41 * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
42 */
43 public final class CleanerImpl implements Runnable {
44
45 /**
46 * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
47 */
48 private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
49
50 /**
51 * Heads of a CleanableList for each reference type.
52 */
53 final PhantomCleanable<?> phantomCleanableList;
54
55 final WeakCleanable<?> weakCleanableList;
56
57 final SoftCleanable<?> softCleanableList;
58
59 // The ReferenceQueue of pending cleaning actions
60 final ReferenceQueue<Object> queue;
61
62 /**
63 * Called by Cleaner static initialization to provide the function
87 public CleanerImpl() {
88 queue = new ReferenceQueue<>();
89 phantomCleanableList = new PhantomCleanableRef();
90 weakCleanableList = new WeakCleanableRef();
91 softCleanableList = new SoftCleanableRef();
92 }
93
94 /**
95 * Starts the Cleaner implementation.
96 * Ensure this is the CleanerImpl for the Cleaner.
97 * When started waits for Cleanables to be queued.
98 * @param cleaner the cleaner
99 * @param threadFactory the thread factory
100 */
101 public void start(Cleaner cleaner, ThreadFactory threadFactory) {
102 if (getCleanerImpl(cleaner) != this) {
103 throw new AssertionError("wrong cleaner");
104 }
105 // schedule a nop cleaning action for the cleaner, so the associated thread
106 // will continue to run at least until the cleaner is reclaimable.
107 new CleanerCleanable(cleaner);
108
109 if (threadFactory == null) {
110 threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
111 }
112
113 // now that there's at least one cleaning action, for the cleaner,
114 // we can start the associated thread, which runs until
115 // all cleaning actions have been run.
116 Thread thread = threadFactory.newThread(this);
117 thread.setDaemon(true);
118 thread.start();
119 }
120
121 /**
122 * Process queued Cleanables as long as the cleanable lists are not empty.
123 * A Cleanable is in one of the lists for each Object and for the Cleaner
124 * itself.
125 * Terminates when the Cleaner is no longer reachable and
126 * has been cleaned and there are no more Cleanable instances
127 * for which the object is reachable.
128 * <p>
129 * If the thread is a ManagedLocalsThread, the threadlocals
130 * are erased before each cleanup
131 */
132 @Override
133 public void run() {
134 Thread t = Thread.currentThread();
135 InnocuousThread mlThread = (t instanceof InnocuousThread)
136 ? (InnocuousThread) t
137 : null;
138 while (!phantomCleanableList.isListEmpty() ||
139 !weakCleanableList.isListEmpty() ||
140 !softCleanableList.isListEmpty()) {
141 if (mlThread != null) {
142 // Clear the thread locals
143 mlThread.eraseThreadLocals();
144 }
145 try {
146 // Wait for a Ref, with a timeout to avoid getting hung
147 // due to a race with clear/clean
148 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
149 if (ref != null) {
150 ref.clean();
151 }
152 } catch (Throwable e) {
153 // ignore exceptions from the cleanup action
154 // (including interruption of cleanup thread)
155 }
156 }
157 }
158
159 /**
160 * Perform cleaning on an unreachable PhantomReference.
161 */
162 public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
163 private final Runnable action;
164
165 /**
166 * Constructor for a phantom cleanable reference.
167 * @param obj the object to monitor
168 * @param cleaner the cleaner
169 * @param action the action Runnable
170 */
171 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
172 super(obj, cleaner);
173 this.action = action;
174 }
304 * @throws UnsupportedOperationException always
305 */
306 @Override
307 public void clear() {
308 throw new UnsupportedOperationException("clear");
309 }
310
311 }
312
313 /**
314 * A ThreadFactory for InnocuousThreads.
315 * The factory is a singleton.
316 */
317 static final class InnocuousThreadFactory implements ThreadFactory {
318 final static ThreadFactory factory = new InnocuousThreadFactory();
319
320 static ThreadFactory factory() {
321 return factory;
322 }
323
324 final AtomicInteger cleanerThreadNumber = new AtomicInteger();
325
326 public Thread newThread(Runnable r) {
327 return AccessController.doPrivileged(new PrivilegedAction<Thread>() {
328 @Override
329 public Thread run() {
330 Thread t = new InnocuousThread(r);
331 t.setPriority(Thread.MAX_PRIORITY - 2);
332 t.setName("Cleaner-" + cleanerThreadNumber.getAndIncrement());
333 return t;
334 }
335 });
336 }
337 }
338
339 /**
340 * A PhantomCleanable implementation for tracking the Cleaner itself.
341 */
342 static final class CleanerCleanable extends PhantomCleanable<Cleaner> {
343 CleanerCleanable(Cleaner cleaner) {
344 super(cleaner, cleaner);
345 }
346
347 @Override
348 protected void performCleanup() {
349 // no action
350 }
351 }
352 }
|