emul/compact/src/main/java/java/lang/ref/Reference.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 28 Jan 2013 18:12:47 +0100
branchjdk7-b147
changeset 601 5198affdb915
child 604 3fcc279c921b
permissions -rw-r--r--
Adding ObjectInputStream and ObjectOutputStream (but without implementation). Adding PropertyChange related classes.
jaroslav@601
     1
/*
jaroslav@601
     2
 * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
jaroslav@601
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@601
     4
 *
jaroslav@601
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@601
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@601
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@601
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@601
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@601
    10
 *
jaroslav@601
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@601
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@601
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@601
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@601
    15
 * accompanied this code).
jaroslav@601
    16
 *
jaroslav@601
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@601
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@601
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@601
    20
 *
jaroslav@601
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@601
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@601
    23
 * questions.
jaroslav@601
    24
 */
jaroslav@601
    25
jaroslav@601
    26
package java.lang.ref;
jaroslav@601
    27
jaroslav@601
    28
import sun.misc.Cleaner;
jaroslav@601
    29
jaroslav@601
    30
jaroslav@601
    31
/**
jaroslav@601
    32
 * Abstract base class for reference objects.  This class defines the
jaroslav@601
    33
 * operations common to all reference objects.  Because reference objects are
jaroslav@601
    34
 * implemented in close cooperation with the garbage collector, this class may
jaroslav@601
    35
 * not be subclassed directly.
jaroslav@601
    36
 *
jaroslav@601
    37
 * @author   Mark Reinhold
jaroslav@601
    38
 * @since    1.2
jaroslav@601
    39
 */
jaroslav@601
    40
jaroslav@601
    41
public abstract class Reference<T> {
jaroslav@601
    42
jaroslav@601
    43
    /* A Reference instance is in one of four possible internal states:
jaroslav@601
    44
     *
jaroslav@601
    45
     *     Active: Subject to special treatment by the garbage collector.  Some
jaroslav@601
    46
     *     time after the collector detects that the reachability of the
jaroslav@601
    47
     *     referent has changed to the appropriate state, it changes the
jaroslav@601
    48
     *     instance's state to either Pending or Inactive, depending upon
jaroslav@601
    49
     *     whether or not the instance was registered with a queue when it was
jaroslav@601
    50
     *     created.  In the former case it also adds the instance to the
jaroslav@601
    51
     *     pending-Reference list.  Newly-created instances are Active.
jaroslav@601
    52
     *
jaroslav@601
    53
     *     Pending: An element of the pending-Reference list, waiting to be
jaroslav@601
    54
     *     enqueued by the Reference-handler thread.  Unregistered instances
jaroslav@601
    55
     *     are never in this state.
jaroslav@601
    56
     *
jaroslav@601
    57
     *     Enqueued: An element of the queue with which the instance was
jaroslav@601
    58
     *     registered when it was created.  When an instance is removed from
jaroslav@601
    59
     *     its ReferenceQueue, it is made Inactive.  Unregistered instances are
jaroslav@601
    60
     *     never in this state.
jaroslav@601
    61
     *
jaroslav@601
    62
     *     Inactive: Nothing more to do.  Once an instance becomes Inactive its
jaroslav@601
    63
     *     state will never change again.
jaroslav@601
    64
     *
jaroslav@601
    65
     * The state is encoded in the queue and next fields as follows:
jaroslav@601
    66
     *
jaroslav@601
    67
     *     Active: queue = ReferenceQueue with which instance is registered, or
jaroslav@601
    68
     *     ReferenceQueue.NULL if it was not registered with a queue; next =
jaroslav@601
    69
     *     null.
jaroslav@601
    70
     *
jaroslav@601
    71
     *     Pending: queue = ReferenceQueue with which instance is registered;
jaroslav@601
    72
     *     next = Following instance in queue, or this if at end of list.
jaroslav@601
    73
     *
jaroslav@601
    74
     *     Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
jaroslav@601
    75
     *     in queue, or this if at end of list.
jaroslav@601
    76
     *
jaroslav@601
    77
     *     Inactive: queue = ReferenceQueue.NULL; next = this.
jaroslav@601
    78
     *
jaroslav@601
    79
     * With this scheme the collector need only examine the next field in order
jaroslav@601
    80
     * to determine whether a Reference instance requires special treatment: If
jaroslav@601
    81
     * the next field is null then the instance is active; if it is non-null,
jaroslav@601
    82
     * then the collector should treat the instance normally.
jaroslav@601
    83
     *
jaroslav@601
    84
     * To ensure that concurrent collector can discover active Reference
jaroslav@601
    85
     * objects without interfering with application threads that may apply
jaroslav@601
    86
     * the enqueue() method to those objects, collectors should link
jaroslav@601
    87
     * discovered objects through the discovered field.
jaroslav@601
    88
     */
jaroslav@601
    89
jaroslav@601
    90
    private T referent;         /* Treated specially by GC */
jaroslav@601
    91
jaroslav@601
    92
    ReferenceQueue<? super T> queue;
jaroslav@601
    93
jaroslav@601
    94
    Reference next;
jaroslav@601
    95
    transient private Reference<T> discovered;  /* used by VM */
jaroslav@601
    96
jaroslav@601
    97
jaroslav@601
    98
    /* Object used to synchronize with the garbage collector.  The collector
jaroslav@601
    99
     * must acquire this lock at the beginning of each collection cycle.  It is
jaroslav@601
   100
     * therefore critical that any code holding this lock complete as quickly
jaroslav@601
   101
     * as possible, allocate no new objects, and avoid calling user code.
jaroslav@601
   102
     */
jaroslav@601
   103
    static private class Lock { };
jaroslav@601
   104
    private static Lock lock = new Lock();
jaroslav@601
   105
jaroslav@601
   106
jaroslav@601
   107
    /* List of References waiting to be enqueued.  The collector adds
jaroslav@601
   108
     * References to this list, while the Reference-handler thread removes
jaroslav@601
   109
     * them.  This list is protected by the above lock object.
jaroslav@601
   110
     */
jaroslav@601
   111
    private static Reference pending = null;
jaroslav@601
   112
jaroslav@601
   113
    /* High-priority thread to enqueue pending References
jaroslav@601
   114
     */
jaroslav@601
   115
    private static class ReferenceHandler extends Thread {
jaroslav@601
   116
jaroslav@601
   117
        ReferenceHandler(ThreadGroup g, String name) {
jaroslav@601
   118
            super(g, name);
jaroslav@601
   119
        }
jaroslav@601
   120
jaroslav@601
   121
        public void run() {
jaroslav@601
   122
            for (;;) {
jaroslav@601
   123
jaroslav@601
   124
                Reference r;
jaroslav@601
   125
                synchronized (lock) {
jaroslav@601
   126
                    if (pending != null) {
jaroslav@601
   127
                        r = pending;
jaroslav@601
   128
                        Reference rn = r.next;
jaroslav@601
   129
                        pending = (rn == r) ? null : rn;
jaroslav@601
   130
                        r.next = r;
jaroslav@601
   131
                    } else {
jaroslav@601
   132
                        try {
jaroslav@601
   133
                            lock.wait();
jaroslav@601
   134
                        } catch (InterruptedException x) { }
jaroslav@601
   135
                        continue;
jaroslav@601
   136
                    }
jaroslav@601
   137
                }
jaroslav@601
   138
jaroslav@601
   139
                // Fast path for cleaners
jaroslav@601
   140
                if (r instanceof Cleaner) {
jaroslav@601
   141
                    ((Cleaner)r).clean();
jaroslav@601
   142
                    continue;
jaroslav@601
   143
                }
jaroslav@601
   144
jaroslav@601
   145
                ReferenceQueue q = r.queue;
jaroslav@601
   146
                if (q != ReferenceQueue.NULL) q.enqueue(r);
jaroslav@601
   147
            }
jaroslav@601
   148
        }
jaroslav@601
   149
    }
jaroslav@601
   150
jaroslav@601
   151
    static {
jaroslav@601
   152
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
jaroslav@601
   153
        for (ThreadGroup tgn = tg;
jaroslav@601
   154
             tgn != null;
jaroslav@601
   155
             tg = tgn, tgn = tg.getParent());
jaroslav@601
   156
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
jaroslav@601
   157
        /* If there were a special system-only priority greater than
jaroslav@601
   158
         * MAX_PRIORITY, it would be used here
jaroslav@601
   159
         */
jaroslav@601
   160
        handler.setPriority(Thread.MAX_PRIORITY);
jaroslav@601
   161
        handler.setDaemon(true);
jaroslav@601
   162
        handler.start();
jaroslav@601
   163
    }
jaroslav@601
   164
jaroslav@601
   165
jaroslav@601
   166
    /* -- Referent accessor and setters -- */
jaroslav@601
   167
jaroslav@601
   168
    /**
jaroslav@601
   169
     * Returns this reference object's referent.  If this reference object has
jaroslav@601
   170
     * been cleared, either by the program or by the garbage collector, then
jaroslav@601
   171
     * this method returns <code>null</code>.
jaroslav@601
   172
     *
jaroslav@601
   173
     * @return   The object to which this reference refers, or
jaroslav@601
   174
     *           <code>null</code> if this reference object has been cleared
jaroslav@601
   175
     */
jaroslav@601
   176
    public T get() {
jaroslav@601
   177
        return this.referent;
jaroslav@601
   178
    }
jaroslav@601
   179
jaroslav@601
   180
    /**
jaroslav@601
   181
     * Clears this reference object.  Invoking this method will not cause this
jaroslav@601
   182
     * object to be enqueued.
jaroslav@601
   183
     *
jaroslav@601
   184
     * <p> This method is invoked only by Java code; when the garbage collector
jaroslav@601
   185
     * clears references it does so directly, without invoking this method.
jaroslav@601
   186
     */
jaroslav@601
   187
    public void clear() {
jaroslav@601
   188
        this.referent = null;
jaroslav@601
   189
    }
jaroslav@601
   190
jaroslav@601
   191
jaroslav@601
   192
    /* -- Queue operations -- */
jaroslav@601
   193
jaroslav@601
   194
    /**
jaroslav@601
   195
     * Tells whether or not this reference object has been enqueued, either by
jaroslav@601
   196
     * the program or by the garbage collector.  If this reference object was
jaroslav@601
   197
     * not registered with a queue when it was created, then this method will
jaroslav@601
   198
     * always return <code>false</code>.
jaroslav@601
   199
     *
jaroslav@601
   200
     * @return   <code>true</code> if and only if this reference object has
jaroslav@601
   201
     *           been enqueued
jaroslav@601
   202
     */
jaroslav@601
   203
    public boolean isEnqueued() {
jaroslav@601
   204
        /* In terms of the internal states, this predicate actually tests
jaroslav@601
   205
           whether the instance is either Pending or Enqueued */
jaroslav@601
   206
        synchronized (this) {
jaroslav@601
   207
            return (this.queue != ReferenceQueue.NULL) && (this.next != null);
jaroslav@601
   208
        }
jaroslav@601
   209
    }
jaroslav@601
   210
jaroslav@601
   211
    /**
jaroslav@601
   212
     * Adds this reference object to the queue with which it is registered,
jaroslav@601
   213
     * if any.
jaroslav@601
   214
     *
jaroslav@601
   215
     * <p> This method is invoked only by Java code; when the garbage collector
jaroslav@601
   216
     * enqueues references it does so directly, without invoking this method.
jaroslav@601
   217
     *
jaroslav@601
   218
     * @return   <code>true</code> if this reference object was successfully
jaroslav@601
   219
     *           enqueued; <code>false</code> if it was already enqueued or if
jaroslav@601
   220
     *           it was not registered with a queue when it was created
jaroslav@601
   221
     */
jaroslav@601
   222
    public boolean enqueue() {
jaroslav@601
   223
        return this.queue.enqueue(this);
jaroslav@601
   224
    }
jaroslav@601
   225
jaroslav@601
   226
jaroslav@601
   227
    /* -- Constructors -- */
jaroslav@601
   228
jaroslav@601
   229
    Reference(T referent) {
jaroslav@601
   230
        this(referent, null);
jaroslav@601
   231
    }
jaroslav@601
   232
jaroslav@601
   233
    Reference(T referent, ReferenceQueue<? super T> queue) {
jaroslav@601
   234
        this.referent = referent;
jaroslav@601
   235
        this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
jaroslav@601
   236
    }
jaroslav@601
   237
jaroslav@601
   238
}