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 }