1 /*
2 * Copyright (c) 2015, 2025, 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 jdk.internal.ref.CleanerImpl;
29
30 import java.util.Objects;
31 import java.util.concurrent.ThreadFactory;
32 import java.util.function.Function;
33
34 /**
35 * {@code Cleaner} manages a set of object references and corresponding cleaning actions.
36 * <p>
37 * Cleaning actions are {@linkplain #register(Object object, Runnable action) registered}
38 * to run after the cleaner is notified that the object has become
39 * phantom reachable.
40 * The cleaner uses {@link PhantomReference} and {@link ReferenceQueue} to be
41 * notified when the {@linkplain java.lang.ref##reachability reachability}
42 * changes.
43 * <p>
44 * Each cleaner operates independently, managing the pending cleaning actions
45 * and handling threading and termination when the cleaner is no longer in use.
46 * Registering an object reference and corresponding cleaning action returns
47 * a {@link Cleanable Cleanable}. The most efficient use is to explicitly invoke
48 * the {@link Cleanable#clean clean} method when the object is closed or
49 * no longer needed.
50 * The cleaning action is a {@link Runnable} to be invoked at most once when
51 * the object has become phantom reachable unless it has already been explicitly cleaned.
52 * Note that the cleaning action must not refer to the object being registered.
53 * If so, the object will not become phantom reachable and the cleaning action
54 * will not be invoked automatically.
55 * <p>
56 * The execution of the cleaning action is performed
57 * by a thread associated with the cleaner.
58 * All exceptions thrown by the cleaning action are ignored.
59 * The cleaner and other cleaning actions are not affected by
60 * exceptions in a cleaning action.
61 * The thread runs until all registered cleaning actions have
62 * completed and the cleaner itself is reclaimed by the garbage collector.
63 * <p>
64 * The behavior of cleaners during {@link System#exit(int) System.exit}
65 * is implementation specific. No guarantees are made relating
66 * to whether cleaning actions are invoked or not.
67 * <p>
68 * Unless otherwise noted, passing a {@code null} argument to a constructor or
69 * method in this class will cause a
70 * {@link java.lang.NullPointerException NullPointerException} to be thrown.
71 *
72 * @apiNote
73 * The cleaning action is invoked only after the associated object becomes
74 * phantom reachable, so it is important that the object implementing the
75 * cleaning action does not hold references to the object.
76 * In this example, a static class encapsulates the cleaning state and action.
77 * An "inner" class, anonymous or not, must not be used because it implicitly
78 * contains a reference to the outer instance, preventing it from becoming
79 * phantom reachable.
80 * The choice of a new cleaner or sharing an existing cleaner is determined
81 * by the use case.
82 * <p>
83 * If the CleaningExample is used in a try-finally block then the
84 * {@code close} method calls the cleaning action.
85 * If the {@code close} method is not called, the cleaning action is called
86 * by the Cleaner when the CleaningExample instance has become phantom reachable.
87 * <pre>{@code
88 * public class CleaningExample implements AutoCloseable {
89 * // A cleaner (preferably one shared within a library,
90 * // but for the sake of example, a new one is created here)
91 * private static final Cleaner cleaner = Cleaner.create();
92 *
93 * // State class captures information necessary for cleanup.
94 * // It must hold no reference to the instance being cleaned
95 * // and therefore it is a static inner class in this example.
96 * static class State implements Runnable {
97 *
98 * State(...) {
99 * // initialize State needed for cleaning action
100 * }
101 *
102 * public void run() {
103 * // cleanup action accessing State, executed at most once
104 * }
105 * }
106 *
107 * private final State state;
108 * private final Cleaner.Cleanable cleanable;
109 *
110 * public CleaningExample() {
111 * this.state = new State(...);
112 * this.cleanable = cleaner.register(this, state);
113 * }
114 *
115 * public void close() {
116 * cleanable.clean();
117 * }
118 * }
119 * }</pre>
120 * The cleaning action could be a lambda but all too easily will capture
121 * the object reference, by referring to fields of the object being cleaned,
122 * preventing the object from becoming phantom reachable.
123 * Using a static nested class, as above, will avoid accidentally retaining the
124 * object reference.
125 * <p>
126 * <a id="compatible-cleaners"></a>
127 * Cleaning actions should be prepared to be invoked concurrently with
128 * other cleaning actions.
129 * Typically the cleaning actions should be very quick to execute
130 * and not block. If the cleaning action blocks, it may delay processing
131 * other cleaning actions registered to the same cleaner.
132 * All cleaning actions registered to a cleaner should be mutually compatible.
133 * @since 9
134 */
135 public final class Cleaner {
136
137 /**
138 * The Cleaner implementation.
139 */
140 final CleanerImpl impl;
141
142 static {
143 CleanerImpl.setCleanerImplAccess(new Function<Cleaner, CleanerImpl>() {
144 @Override
145 public CleanerImpl apply(Cleaner cleaner) {
146 return cleaner.impl;
147 }
148 });
149 }
150
151 /**
152 * Construct a Cleaner implementation and start it.
153 */
154 private Cleaner() {
155 impl = new CleanerImpl();
156 }
157
158 /**
159 * Returns a new {@code Cleaner}.
160 * <p>
161 * The cleaner creates a {@link Thread#setDaemon(boolean) daemon thread}
162 * to process the phantom reachable objects and to invoke cleaning actions.
163 * The {@linkplain java.lang.Thread#getContextClassLoader context class loader}
164 * of the thread is set to the
165 * {@linkplain ClassLoader#getSystemClassLoader() system class loader}.
166 * <p>
167 * The cleaner terminates when it is phantom reachable and all of the
168 * registered cleaning actions are complete.
169 *
170 * @return a new {@code Cleaner}
171 */
172 public static Cleaner create() {
173 Cleaner cleaner = new Cleaner();
174 cleaner.impl.start(cleaner, null);
175 return cleaner;
176 }
177
178 /**
179 * Returns a new {@code Cleaner} using a {@code Thread} from the {@code ThreadFactory}.
180 * <p>
181 * A thread from the thread factory's {@link ThreadFactory#newThread(Runnable) newThread}
182 * method is set to be a {@linkplain Thread#setDaemon(boolean) daemon thread}
183 * and started to process phantom reachable objects and invoke cleaning actions.
184 * On each call the {@linkplain ThreadFactory#newThread(Runnable) thread factory}
185 * must provide a Thread that is suitable for performing the cleaning actions.
186 * <p>
187 * The cleaner terminates when it is phantom reachable and all of the
188 * registered cleaning actions are complete.
189 *
190 * @param threadFactory a {@code ThreadFactory} to return a new {@code Thread}
191 * to process cleaning actions
192 * @return a new {@code Cleaner}
193 *
194 * @throws IllegalThreadStateException if the thread from the thread
195 * factory was {@linkplain Thread.State#NEW not a new thread}.
196 */
197 public static Cleaner create(ThreadFactory threadFactory) {
198 Objects.requireNonNull(threadFactory, "threadFactory");
199 Cleaner cleaner = new Cleaner();
200 cleaner.impl.start(cleaner, threadFactory);
201 return cleaner;
202 }
203
204 /**
205 * Registers an object and a cleaning action to run when the object
206 * becomes phantom reachable.
207 * Refer to the <a href="#compatible-cleaners">API Note</a> above for
208 * cautions about the behavior of cleaning actions.
209 *
210 * <p>The given object is kept strongly reachable (and therefore not eligible
211 * for cleaning) during the register() method.
212 *
213 * <p>{@linkplain java.lang.ref##MemoryConsistency Memory consistency effects}:
214 * Actions in a thread prior to calling {@code Cleaner.register()}
215 * <a href="{@docRoot}/java.base/java/util/concurrent/package-summary.html#MemoryVisibility"><i>happen-before</i></a>
216 * the cleaning action is run by the Cleaner's thread.
217 *
218 * @param obj the object to monitor
219 * @param action a {@code Runnable} to invoke when the object becomes phantom reachable
220 * @return a {@code Cleanable} instance
221 * @throws IdentityException if the object is not an
222 * {@link java.util.Objects#hasIdentity(Object) identity object}
223 */
224 public Cleanable register(@jdk.internal.RequiresIdentity Object obj, Runnable action) {
225 Objects.requireIdentity(obj, "obj");
226 Objects.requireNonNull(action, "action");
227 return new CleanerImpl.PhantomCleanableRef(obj, this, action);
228 }
229
230 /**
231 * {@code Cleanable} represents an object and a
232 * cleaning action registered in a {@code Cleaner}.
233 * @since 9
234 */
235 public interface Cleanable {
236 /**
237 * Unregisters the cleanable and invokes the cleaning action.
238 * The cleanable's cleaning action is invoked at most once
239 * regardless of the number of calls to {@code clean}.
240 */
241 void clean();
242 }
243
244 }