jaroslav@601: /* jaroslav@601: * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. jaroslav@601: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@601: * jaroslav@601: * This code is free software; you can redistribute it and/or modify it jaroslav@601: * under the terms of the GNU General Public License version 2 only, as jaroslav@601: * published by the Free Software Foundation. Oracle designates this jaroslav@601: * particular file as subject to the "Classpath" exception as provided jaroslav@601: * by Oracle in the LICENSE file that accompanied this code. jaroslav@601: * jaroslav@601: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@601: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@601: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@601: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@601: * accompanied this code). jaroslav@601: * jaroslav@601: * You should have received a copy of the GNU General Public License version jaroslav@601: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@601: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@601: * jaroslav@601: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@601: * or visit www.oracle.com if you need additional information or have any jaroslav@601: * questions. jaroslav@601: */ jaroslav@601: jaroslav@601: package java.lang.ref; jaroslav@601: jaroslav@601: /** jaroslav@601: * Reference queues, to which registered reference objects are appended by the jaroslav@601: * garbage collector after the appropriate reachability changes are detected. jaroslav@601: * jaroslav@601: * @author Mark Reinhold jaroslav@601: * @since 1.2 jaroslav@601: */ jaroslav@601: jaroslav@601: public class ReferenceQueue { jaroslav@601: jaroslav@601: /** jaroslav@601: * Constructs a new reference-object queue. jaroslav@601: */ jaroslav@601: public ReferenceQueue() { } jaroslav@601: jaroslav@601: private static class Null extends ReferenceQueue { jaroslav@601: boolean enqueue(Reference r) { jaroslav@601: return false; jaroslav@601: } jaroslav@601: } jaroslav@601: jaroslav@601: static ReferenceQueue NULL = new Null(); jaroslav@601: static ReferenceQueue ENQUEUED = new Null(); jaroslav@601: jaroslav@601: static private class Lock { }; jaroslav@601: private Lock lock = new Lock(); jaroslav@601: private volatile Reference head = null; jaroslav@601: private long queueLength = 0; jaroslav@601: jaroslav@601: boolean enqueue(Reference r) { /* Called only by Reference class */ jaroslav@601: synchronized (r) { jaroslav@601: if (r.queue == ENQUEUED) return false; jaroslav@601: synchronized (lock) { jaroslav@601: r.queue = ENQUEUED; jaroslav@601: r.next = (head == null) ? r : head; jaroslav@601: head = r; jaroslav@601: queueLength++; jaroslav@601: lock.notifyAll(); jaroslav@601: return true; jaroslav@601: } jaroslav@601: } jaroslav@601: } jaroslav@601: jaroslav@601: private Reference reallyPoll() { /* Must hold lock */ jaroslav@601: if (head != null) { jaroslav@601: Reference r = head; jaroslav@601: head = (r.next == r) ? null : r.next; jaroslav@601: r.queue = NULL; jaroslav@601: r.next = r; jaroslav@601: queueLength--; jaroslav@601: return r; jaroslav@601: } jaroslav@601: return null; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Polls this queue to see if a reference object is available. If one is jaroslav@601: * available without further delay then it is removed from the queue and jaroslav@601: * returned. Otherwise this method immediately returns null. jaroslav@601: * jaroslav@601: * @return A reference object, if one was immediately available, jaroslav@601: * otherwise null jaroslav@601: */ jaroslav@601: public Reference poll() { jaroslav@601: if (head == null) jaroslav@601: return null; jaroslav@601: synchronized (lock) { jaroslav@601: return reallyPoll(); jaroslav@601: } jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Removes the next reference object in this queue, blocking until either jaroslav@601: * one becomes available or the given timeout period expires. jaroslav@601: * jaroslav@601: *

This method does not offer real-time guarantees: It schedules the jaroslav@601: * timeout as if by invoking the {@link Object#wait(long)} method. jaroslav@601: * jaroslav@601: * @param timeout If positive, block for up to timeout jaroslav@601: * milliseconds while waiting for a reference to be jaroslav@601: * added to this queue. If zero, block indefinitely. jaroslav@601: * jaroslav@601: * @return A reference object, if one was available within the specified jaroslav@601: * timeout period, otherwise null jaroslav@601: * jaroslav@601: * @throws IllegalArgumentException jaroslav@601: * If the value of the timeout argument is negative jaroslav@601: * jaroslav@601: * @throws InterruptedException jaroslav@601: * If the timeout wait is interrupted jaroslav@601: */ jaroslav@601: public Reference remove(long timeout) jaroslav@601: throws IllegalArgumentException, InterruptedException jaroslav@601: { jaroslav@601: if (timeout < 0) { jaroslav@601: throw new IllegalArgumentException("Negative timeout value"); jaroslav@601: } jaroslav@601: synchronized (lock) { jaroslav@601: Reference r = reallyPoll(); jaroslav@601: if (r != null) return r; jaroslav@601: for (;;) { jaroslav@601: lock.wait(timeout); jaroslav@601: r = reallyPoll(); jaroslav@601: if (r != null) return r; jaroslav@601: if (timeout != 0) return null; jaroslav@601: } jaroslav@601: } jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Removes the next reference object in this queue, blocking until one jaroslav@601: * becomes available. jaroslav@601: * jaroslav@601: * @return A reference object, blocking until one becomes available jaroslav@601: * @throws InterruptedException If the wait is interrupted jaroslav@601: */ jaroslav@601: public Reference remove() throws InterruptedException { jaroslav@601: return remove(0); jaroslav@601: } jaroslav@601: jaroslav@601: }