0N/A/*
2362N/A * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.lang.ref;
0N/A
0N/Aimport sun.misc.Cleaner;
0N/A
0N/A
0N/A/**
0N/A * Abstract base class for reference objects. This class defines the
0N/A * operations common to all reference objects. Because reference objects are
0N/A * implemented in close cooperation with the garbage collector, this class may
0N/A * not be subclassed directly.
0N/A *
0N/A * @author Mark Reinhold
0N/A * @since 1.2
0N/A */
0N/A
0N/Apublic abstract class Reference<T> {
0N/A
0N/A /* A Reference instance is in one of four possible internal states:
0N/A *
0N/A * Active: Subject to special treatment by the garbage collector. Some
0N/A * time after the collector detects that the reachability of the
0N/A * referent has changed to the appropriate state, it changes the
0N/A * instance's state to either Pending or Inactive, depending upon
0N/A * whether or not the instance was registered with a queue when it was
0N/A * created. In the former case it also adds the instance to the
0N/A * pending-Reference list. Newly-created instances are Active.
0N/A *
0N/A * Pending: An element of the pending-Reference list, waiting to be
0N/A * enqueued by the Reference-handler thread. Unregistered instances
0N/A * are never in this state.
0N/A *
0N/A * Enqueued: An element of the queue with which the instance was
0N/A * registered when it was created. When an instance is removed from
0N/A * its ReferenceQueue, it is made Inactive. Unregistered instances are
0N/A * never in this state.
0N/A *
0N/A * Inactive: Nothing more to do. Once an instance becomes Inactive its
0N/A * state will never change again.
0N/A *
0N/A * The state is encoded in the queue and next fields as follows:
0N/A *
0N/A * Active: queue = ReferenceQueue with which instance is registered, or
0N/A * ReferenceQueue.NULL if it was not registered with a queue; next =
0N/A * null.
0N/A *
0N/A * Pending: queue = ReferenceQueue with which instance is registered;
0N/A * next = Following instance in queue, or this if at end of list.
0N/A *
0N/A * Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
0N/A * in queue, or this if at end of list.
0N/A *
0N/A * Inactive: queue = ReferenceQueue.NULL; next = this.
0N/A *
0N/A * With this scheme the collector need only examine the next field in order
0N/A * to determine whether a Reference instance requires special treatment: If
0N/A * the next field is null then the instance is active; if it is non-null,
0N/A * then the collector should treat the instance normally.
0N/A *
0N/A * To ensure that concurrent collector can discover active Reference
0N/A * objects without interfering with application threads that may apply
0N/A * the enqueue() method to those objects, collectors should link
0N/A * discovered objects through the discovered field.
0N/A */
0N/A
0N/A private T referent; /* Treated specially by GC */
0N/A
0N/A ReferenceQueue<? super T> queue;
0N/A
0N/A Reference next;
0N/A transient private Reference<T> discovered; /* used by VM */
0N/A
0N/A
0N/A /* Object used to synchronize with the garbage collector. The collector
0N/A * must acquire this lock at the beginning of each collection cycle. It is
0N/A * therefore critical that any code holding this lock complete as quickly
0N/A * as possible, allocate no new objects, and avoid calling user code.
0N/A */
0N/A static private class Lock { };
0N/A private static Lock lock = new Lock();
0N/A
0N/A
0N/A /* List of References waiting to be enqueued. The collector adds
0N/A * References to this list, while the Reference-handler thread removes
0N/A * them. This list is protected by the above lock object.
0N/A */
0N/A private static Reference pending = null;
0N/A
0N/A /* High-priority thread to enqueue pending References
0N/A */
0N/A private static class ReferenceHandler extends Thread {
0N/A
0N/A ReferenceHandler(ThreadGroup g, String name) {
0N/A super(g, name);
0N/A }
0N/A
0N/A public void run() {
0N/A for (;;) {
0N/A
0N/A Reference r;
0N/A synchronized (lock) {
0N/A if (pending != null) {
0N/A r = pending;
0N/A Reference rn = r.next;
0N/A pending = (rn == r) ? null : rn;
0N/A r.next = r;
0N/A } else {
0N/A try {
0N/A lock.wait();
0N/A } catch (InterruptedException x) { }
0N/A continue;
0N/A }
0N/A }
0N/A
0N/A // Fast path for cleaners
0N/A if (r instanceof Cleaner) {
0N/A ((Cleaner)r).clean();
0N/A continue;
0N/A }
0N/A
0N/A ReferenceQueue q = r.queue;
0N/A if (q != ReferenceQueue.NULL) q.enqueue(r);
0N/A }
0N/A }
0N/A }
0N/A
0N/A static {
0N/A ThreadGroup tg = Thread.currentThread().getThreadGroup();
0N/A for (ThreadGroup tgn = tg;
0N/A tgn != null;
0N/A tg = tgn, tgn = tg.getParent());
0N/A Thread handler = new ReferenceHandler(tg, "Reference Handler");
0N/A /* If there were a special system-only priority greater than
0N/A * MAX_PRIORITY, it would be used here
0N/A */
0N/A handler.setPriority(Thread.MAX_PRIORITY);
0N/A handler.setDaemon(true);
0N/A handler.start();
0N/A }
0N/A
0N/A
0N/A /* -- Referent accessor and setters -- */
0N/A
0N/A /**
0N/A * Returns this reference object's referent. If this reference object has
0N/A * been cleared, either by the program or by the garbage collector, then
0N/A * this method returns <code>null</code>.
0N/A *
0N/A * @return The object to which this reference refers, or
0N/A * <code>null</code> if this reference object has been cleared
0N/A */
0N/A public T get() {
0N/A return this.referent;
0N/A }
0N/A
0N/A /**
0N/A * Clears this reference object. Invoking this method will not cause this
0N/A * object to be enqueued.
0N/A *
0N/A * <p> This method is invoked only by Java code; when the garbage collector
0N/A * clears references it does so directly, without invoking this method.
0N/A */
0N/A public void clear() {
0N/A this.referent = null;
0N/A }
0N/A
0N/A
0N/A /* -- Queue operations -- */
0N/A
0N/A /**
0N/A * Tells whether or not this reference object has been enqueued, either by
0N/A * the program or by the garbage collector. If this reference object was
0N/A * not registered with a queue when it was created, then this method will
0N/A * always return <code>false</code>.
0N/A *
0N/A * @return <code>true</code> if and only if this reference object has
0N/A * been enqueued
0N/A */
0N/A public boolean isEnqueued() {
0N/A /* In terms of the internal states, this predicate actually tests
0N/A whether the instance is either Pending or Enqueued */
0N/A synchronized (this) {
0N/A return (this.queue != ReferenceQueue.NULL) && (this.next != null);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Adds this reference object to the queue with which it is registered,
0N/A * if any.
0N/A *
0N/A * <p> This method is invoked only by Java code; when the garbage collector
0N/A * enqueues references it does so directly, without invoking this method.
0N/A *
0N/A * @return <code>true</code> if this reference object was successfully
0N/A * enqueued; <code>false</code> if it was already enqueued or if
0N/A * it was not registered with a queue when it was created
0N/A */
0N/A public boolean enqueue() {
0N/A return this.queue.enqueue(this);
0N/A }
0N/A
0N/A
0N/A /* -- Constructors -- */
0N/A
0N/A Reference(T referent) {
0N/A this(referent, null);
0N/A }
0N/A
0N/A Reference(T referent, ReferenceQueue<? super T> queue) {
0N/A this.referent = referent;
0N/A this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
0N/A }
0N/A
0N/A}