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