1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
/* * @(#)ReferenceQueue.java 1.25 05/11/17 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.lang.ref; /** * Reference queues, to which registered reference objects are appended by the * garbage collector after the appropriate reachability changes are detected. * * @version 1.25, 11/17/05 * @author Mark Reinhold * @since 1.2 */ public class ReferenceQueue<T> { /** * Constructs a new reference-object queue. */ public ReferenceQueue() { } private static class Null extends ReferenceQueue { boolean enqueue(Reference r) { return false; } } static ReferenceQueue NULL = new Null(); static ReferenceQueue ENQUEUED = new Null(); static private class Lock { }; private Lock lock = new Lock(); private Reference<? extends T> head = null; private long queueLength = 0; boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ synchronized (r) { if (r.queue == ENQUEUED) return false; synchronized (lock) { r.queue = ENQUEUED; r.next = (head == null) ? r : head; head = r; queueLength++; if (r instanceof FinalReference) { sun.misc.VM.addFinalRefCount(1); } lock.notifyAll(); return true; } } } private Reference<? extends T> reallyPoll() { /* Must hold lock */ if (head != null) { Reference<? extends T> r = head; head = (r.next == r) ? null : r.next; r.queue = NULL; r.next = r; queueLength--; if (r instanceof FinalReference) { sun.misc.VM.addFinalRefCount(-1); } return r; } return null; } /** * Polls this queue to see if a reference object is available. If one is * available without further delay then it is removed from the queue and * returned. Otherwise this method immediately returns <tt>null</tt>. * * @return A reference object, if one was immediately available, * otherwise <code>null</code> */ public Reference<? extends T> poll() { synchronized (lock) { return reallyPoll(); } } /** * Removes the next reference object in this queue, blocking until either * one becomes available or the given timeout period expires. * * <p> This method does not offer real-time guarantees: It schedules the * timeout as if by invoking the {@link Object#wait(long)} method. * * @param timeout If positive, block for up to <code>timeout</code> * milliseconds while waiting for a reference to be * added to this queue. If zero, block indefinitely. * * @return A reference object, if one was available within the specified * timeout period, otherwise <code>null</code> * * @throws IllegalArgumentException * If the value of the timeout argument is negative * * @throws InterruptedException * If the timeout wait is interrupted */ public Reference<? extends T> remove(long timeout) throws IllegalArgumentException, InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("Negative timeout value"); } synchronized (lock) { Reference<? extends T> r = reallyPoll(); if (r != null) return r; for (;;) { lock.wait(timeout); r = reallyPoll(); if (r != null) return r; if (timeout != 0) return null; } } } /** * Removes the next reference object in this queue, blocking until one * becomes available. * * @return A reference object, blocking until one becomes available * @throws InterruptedException If the wait is interrupted */ public Reference<? extends T> remove() throws InterruptedException { return remove(0); } }