1. /*
  2. * @(#)Reference.java 1.41 04/04/20
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.lang.ref;
  8. import sun.misc.Cleaner;
  9. /**
  10. * Abstract base class for reference objects. This class defines the
  11. * operations common to all reference objects. Because reference objects are
  12. * implemented in close cooperation with the garbage collector, this class may
  13. * not be subclassed directly.
  14. *
  15. * @version 1.41, 04/20/04
  16. * @author Mark Reinhold
  17. * @since 1.2
  18. */
  19. public abstract class Reference<T> {
  20. /* A Reference instance is in one of four possible internal states:
  21. *
  22. * Active: Subject to special treatment by the garbage collector. Some
  23. * time after the collector detects that the reachability of the
  24. * referent has changed to the appropriate state, it changes the
  25. * instance's state to either Pending or Inactive, depending upon
  26. * whether or not the instance was registered with a queue when it was
  27. * created. In the former case it also adds the instance to the
  28. * pending-Reference list. Newly-created instances are Active.
  29. *
  30. * Pending: An element of the pending-Reference list, waiting to be
  31. * enqueued by the Reference-handler thread. Unregistered instances
  32. * are never in this state.
  33. *
  34. * Enqueued: An element of the queue with which the instance was
  35. * registered when it was created. When an instance is removed from
  36. * its ReferenceQueue, it is made Inactive. Unregistered instances are
  37. * never in this state.
  38. *
  39. * Inactive: Nothing more to do. Once an instance becomes Inactive its
  40. * state will never change again.
  41. *
  42. * The state is encoded in the queue and next fields as follows:
  43. *
  44. * Active: queue = ReferenceQueue with which instance is registered, or
  45. * ReferenceQueue.NULL if it was not registered with a queue; next =
  46. * null.
  47. *
  48. * Pending: queue = ReferenceQueue with which instance is registered;
  49. * next = Following instance in queue, or this if at end of list.
  50. *
  51. * Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
  52. * in queue, or this if at end of list.
  53. *
  54. * Inactive: queue = ReferenceQueue.NULL; next = this.
  55. *
  56. * With this scheme the collector need only examine the next field in order
  57. * to determine whether a Reference instance requires special treatment: If
  58. * the next field is null then the instance is active; if it is non-null,
  59. * then the collector should treat the instance normally.
  60. *
  61. * To ensure that concurrent collector can discover active Reference
  62. * objects without interfering with application threads that may apply
  63. * the enqueue() method to those objects, collectors should link
  64. * discovered objects through the discovered field.
  65. */
  66. private T referent; /* Treated specially by GC */
  67. ReferenceQueue<? super T> queue;
  68. Reference next;
  69. transient private Reference<T> discovered; /* used by VM */
  70. /* Object used to synchronize with the garbage collector. The collector
  71. * must acquire this lock at the beginning of each collection cycle. It is
  72. * therefore critical that any code holding this lock complete as quickly
  73. * as possible, allocate no new objects, and avoid calling user code.
  74. */
  75. static private class Lock { };
  76. private static Lock lock = new Lock();
  77. /* List of References waiting to be enqueued. The collector adds
  78. * References to this list, while the Reference-handler thread removes
  79. * them. This list is protected by the above lock object.
  80. */
  81. private static Reference pending = null;
  82. /* High-priority thread to enqueue pending References
  83. */
  84. private static class ReferenceHandler extends Thread {
  85. ReferenceHandler(ThreadGroup g, String name) {
  86. super(g, name);
  87. }
  88. public void run() {
  89. for (;;) {
  90. Reference r;
  91. synchronized (lock) {
  92. if (pending != null) {
  93. r = pending;
  94. Reference rn = r.next;
  95. pending = (rn == r) ? null : rn;
  96. r.next = r;
  97. } else {
  98. try {
  99. lock.wait();
  100. } catch (InterruptedException x) { }
  101. continue;
  102. }
  103. }
  104. // Fast path for cleaners
  105. if (r instanceof Cleaner) {
  106. ((Cleaner)r).clean();
  107. continue;
  108. }
  109. ReferenceQueue q = r.queue;
  110. if (q != ReferenceQueue.NULL) q.enqueue(r);
  111. }
  112. }
  113. }
  114. static {
  115. ThreadGroup tg = Thread.currentThread().getThreadGroup();
  116. for (ThreadGroup tgn = tg;
  117. tgn != null;
  118. tg = tgn, tgn = tg.getParent());
  119. Thread handler = new ReferenceHandler(tg, "Reference Handler");
  120. /* If there were a special system-only priority greater than
  121. * MAX_PRIORITY, it would be used here
  122. */
  123. handler.setPriority(Thread.MAX_PRIORITY);
  124. handler.setDaemon(true);
  125. handler.start();
  126. }
  127. /* -- Referent accessor and setters -- */
  128. /**
  129. * Returns this reference object's referent. If this reference object has
  130. * been cleared, either by the program or by the garbage collector, then
  131. * this method returns <code>null</code>.
  132. *
  133. * @return The object to which this reference refers, or
  134. * <code>null</code> if this reference object has been cleared
  135. */
  136. public T get() {
  137. return this.referent;
  138. }
  139. /**
  140. * Clears this reference object. Invoking this method will not cause this
  141. * object to be enqueued.
  142. */
  143. public void clear() {
  144. this.referent = null;
  145. }
  146. /* -- Queue operations -- */
  147. /**
  148. * Tells whether or not this reference object has been enqueued, either by
  149. * the program or by the garbage collector. If this reference object was
  150. * not registered with a queue when it was created, then this method will
  151. * always return <code>false</code>.
  152. *
  153. * @return <code>true</code> if and only if this reference object has
  154. * been enqueued
  155. */
  156. public boolean isEnqueued() {
  157. /* In terms of the internal states, this predicate actually tests
  158. whether the instance is either Pending or Enqueued */
  159. synchronized (this) {
  160. return (this.queue != ReferenceQueue.NULL) && (this.next != null);
  161. }
  162. }
  163. /**
  164. * Adds this reference object to the queue with which it is registered,
  165. * if any.
  166. *
  167. * @return <code>true</code> if this reference object was successfully
  168. * enqueued; <code>false</code> if it was already enqueued or if
  169. * it was not registered with a queue when it was created
  170. */
  171. public boolean enqueue() {
  172. return this.queue.enqueue(this);
  173. }
  174. /* -- Constructors -- */
  175. Reference(T referent) {
  176. this(referent, null);
  177. }
  178. Reference(T referent, ReferenceQueue<? super T> queue) {
  179. this.referent = referent;
  180. this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
  181. }
  182. }