Reference.java revision 12745:f068a4ffddd2
1/*
2 * Copyright (c) 1997, 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
26package java.lang.ref;
27
28import sun.misc.Cleaner;
29import sun.misc.JavaLangRefAccess;
30import sun.misc.ManagedLocalsThread;
31import sun.misc.SharedSecrets;
32import jdk.internal.HotSpotIntrinsicCandidate;
33
34/**
35 * Abstract base class for reference objects.  This class defines the
36 * operations common to all reference objects.  Because reference objects are
37 * implemented in close cooperation with the garbage collector, this class may
38 * not be subclassed directly.
39 *
40 * @author   Mark Reinhold
41 * @since    1.2
42 */
43
44public abstract class Reference<T> {
45
46    /* A Reference instance is in one of four possible internal states:
47     *
48     *     Active: Subject to special treatment by the garbage collector.  Some
49     *     time after the collector detects that the reachability of the
50     *     referent has changed to the appropriate state, it changes the
51     *     instance's state to either Pending or Inactive, depending upon
52     *     whether or not the instance was registered with a queue when it was
53     *     created.  In the former case it also adds the instance to the
54     *     pending-Reference list.  Newly-created instances are Active.
55     *
56     *     Pending: An element of the pending-Reference list, waiting to be
57     *     enqueued by the Reference-handler thread.  Unregistered instances
58     *     are never in this state.
59     *
60     *     Enqueued: An element of the queue with which the instance was
61     *     registered when it was created.  When an instance is removed from
62     *     its ReferenceQueue, it is made Inactive.  Unregistered instances are
63     *     never in this state.
64     *
65     *     Inactive: Nothing more to do.  Once an instance becomes Inactive its
66     *     state will never change again.
67     *
68     * The state is encoded in the queue and next fields as follows:
69     *
70     *     Active: queue = ReferenceQueue with which instance is registered, or
71     *     ReferenceQueue.NULL if it was not registered with a queue; next =
72     *     null.
73     *
74     *     Pending: queue = ReferenceQueue with which instance is registered;
75     *     next = this
76     *
77     *     Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
78     *     in queue, or this if at end of list.
79     *
80     *     Inactive: queue = ReferenceQueue.NULL; next = this.
81     *
82     * With this scheme the collector need only examine the next field in order
83     * to determine whether a Reference instance requires special treatment: If
84     * the next field is null then the instance is active; if it is non-null,
85     * then the collector should treat the instance normally.
86     *
87     * To ensure that a concurrent collector can discover active Reference
88     * objects without interfering with application threads that may apply
89     * the enqueue() method to those objects, collectors should link
90     * discovered objects through the discovered field. The discovered
91     * field is also used for linking Reference objects in the pending list.
92     */
93
94    private T referent;         /* Treated specially by GC */
95
96    volatile ReferenceQueue<? super T> queue;
97
98    /* When active:   NULL
99     *     pending:   this
100     *    Enqueued:   next reference in queue (or this if last)
101     *    Inactive:   this
102     */
103    @SuppressWarnings("rawtypes")
104    volatile Reference next;
105
106    /* When active:   next element in a discovered reference list maintained by GC (or this if last)
107     *     pending:   next element in the pending list (or null if last)
108     *   otherwise:   NULL
109     */
110    private transient Reference<T> discovered;  /* used by VM */
111
112
113    /* Object used to synchronize with the garbage collector.  The collector
114     * must acquire this lock at the beginning of each collection cycle.  It is
115     * therefore critical that any code holding this lock complete as quickly
116     * as possible, allocate no new objects, and avoid calling user code.
117     */
118    private static class Lock { }
119    private static Lock lock = new Lock();
120
121
122    /* List of References waiting to be enqueued.  The collector adds
123     * References to this list, while the Reference-handler thread removes
124     * them.  This list is protected by the above lock object. The
125     * list uses the discovered field to link its elements.
126     */
127    private static Reference<Object> pending = null;
128
129    /* High-priority thread to enqueue pending References
130     */
131    private static class ReferenceHandler extends ManagedLocalsThread {
132
133        private static void ensureClassInitialized(Class<?> clazz) {
134            try {
135                Class.forName(clazz.getName(), true, clazz.getClassLoader());
136            } catch (ClassNotFoundException e) {
137                throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
138            }
139        }
140
141        static {
142            // pre-load and initialize InterruptedException and Cleaner classes
143            // so that we don't get into trouble later in the run loop if there's
144            // memory shortage while loading/initializing them lazily.
145            ensureClassInitialized(InterruptedException.class);
146            ensureClassInitialized(Cleaner.class);
147        }
148
149        ReferenceHandler(ThreadGroup g, String name) {
150            super(g, name);
151        }
152
153        public void run() {
154            while (true) {
155                tryHandlePending(true);
156            }
157        }
158    }
159
160    /**
161     * Try handle pending {@link Reference} if there is one.<p>
162     * Return {@code true} as a hint that there might be another
163     * {@link Reference} pending or {@code false} when there are no more pending
164     * {@link Reference}s at the moment and the program can do some other
165     * useful work instead of looping.
166     *
167     * @param waitForNotify if {@code true} and there was no pending
168     *                      {@link Reference}, wait until notified from VM
169     *                      or interrupted; if {@code false}, return immediately
170     *                      when there is no pending {@link Reference}.
171     * @return {@code true} if there was a {@link Reference} pending and it
172     *         was processed, or we waited for notification and either got it
173     *         or thread was interrupted before being notified;
174     *         {@code false} otherwise.
175     */
176    static boolean tryHandlePending(boolean waitForNotify) {
177        Reference<Object> r;
178        Cleaner c;
179        try {
180            synchronized (lock) {
181                if (pending != null) {
182                    r = pending;
183                    // 'instanceof' might throw OutOfMemoryError sometimes
184                    // so do this before un-linking 'r' from the 'pending' chain...
185                    c = r instanceof Cleaner ? (Cleaner) r : null;
186                    // unlink 'r' from 'pending' chain
187                    pending = r.discovered;
188                    r.discovered = null;
189                } else {
190                    // The waiting on the lock may cause an OutOfMemoryError
191                    // because it may try to allocate exception objects.
192                    if (waitForNotify) {
193                        lock.wait();
194                    }
195                    // retry if waited
196                    return waitForNotify;
197                }
198            }
199        } catch (OutOfMemoryError x) {
200            // Give other threads CPU time so they hopefully drop some live references
201            // and GC reclaims some space.
202            // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
203            // persistently throws OOME for some time...
204            Thread.yield();
205            // retry
206            return true;
207        } catch (InterruptedException x) {
208            // retry
209            return true;
210        }
211
212        // Fast path for cleaners
213        if (c != null) {
214            c.clean();
215            return true;
216        }
217
218        ReferenceQueue<? super Object> q = r.queue;
219        if (q != ReferenceQueue.NULL) q.enqueue(r);
220        return true;
221    }
222
223    static {
224        ThreadGroup tg = Thread.currentThread().getThreadGroup();
225        for (ThreadGroup tgn = tg;
226             tgn != null;
227             tg = tgn, tgn = tg.getParent());
228        Thread handler = new ReferenceHandler(tg, "Reference Handler");
229        /* If there were a special system-only priority greater than
230         * MAX_PRIORITY, it would be used here
231         */
232        handler.setPriority(Thread.MAX_PRIORITY);
233        handler.setDaemon(true);
234        handler.start();
235
236        // provide access in SharedSecrets
237        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
238            @Override
239            public boolean tryHandlePendingReference() {
240                return tryHandlePending(false);
241            }
242        });
243    }
244
245    /* -- Referent accessor and setters -- */
246
247    /**
248     * Returns this reference object's referent.  If this reference object has
249     * been cleared, either by the program or by the garbage collector, then
250     * this method returns <code>null</code>.
251     *
252     * @return   The object to which this reference refers, or
253     *           <code>null</code> if this reference object has been cleared
254     */
255    @HotSpotIntrinsicCandidate
256    public T get() {
257        return this.referent;
258    }
259
260    /**
261     * Clears this reference object.  Invoking this method will not cause this
262     * object to be enqueued.
263     *
264     * <p> This method is invoked only by Java code; when the garbage collector
265     * clears references it does so directly, without invoking this method.
266     */
267    public void clear() {
268        this.referent = null;
269    }
270
271
272    /* -- Queue operations -- */
273
274    /**
275     * Tells whether or not this reference object has been enqueued, either by
276     * the program or by the garbage collector.  If this reference object was
277     * not registered with a queue when it was created, then this method will
278     * always return <code>false</code>.
279     *
280     * @return   <code>true</code> if and only if this reference object has
281     *           been enqueued
282     */
283    public boolean isEnqueued() {
284        return (this.queue == ReferenceQueue.ENQUEUED);
285    }
286
287    /**
288     * Adds this reference object to the queue with which it is registered,
289     * if any.
290     *
291     * <p> This method is invoked only by Java code; when the garbage collector
292     * enqueues references it does so directly, without invoking this method.
293     *
294     * @return   <code>true</code> if this reference object was successfully
295     *           enqueued; <code>false</code> if it was already enqueued or if
296     *           it was not registered with a queue when it was created
297     */
298    public boolean enqueue() {
299        return this.queue.enqueue(this);
300    }
301
302
303    /* -- Constructors -- */
304
305    Reference(T referent) {
306        this(referent, null);
307    }
308
309    Reference(T referent, ReferenceQueue<? super T> queue) {
310        this.referent = referent;
311        this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
312    }
313
314}
315