< prev index next >

src/java.base/share/classes/java/lang/ref/ReferenceQueue.java

Print this page

        

*** 44,98 **** boolean enqueue(Reference<? extends S> r) { return false; } } ! static ReferenceQueue<Object> NULL = new Null<>(); ! static ReferenceQueue<Object> ENQUEUED = new Null<>(); ! static private class Lock { }; ! private Lock lock = new Lock(); ! private volatile Reference<? extends T> head = null; ! private long queueLength = 0; boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ ! synchronized (lock) { ! // Check that since getting the lock this reference hasn't already been // enqueued (and even then removed) ! ReferenceQueue<?> queue = r.queue; if ((queue == NULL) || (queue == ENQUEUED)) { return false; } assert queue == this; ! 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; } } ! @SuppressWarnings("unchecked") ! private Reference<? extends T> reallyPoll() { /* Must hold lock */ ! Reference<? extends T> r = head; ! if (r != null) { ! head = (r.next == r) ? ! null : ! r.next; // Unchecked due to the next field having a raw type in Reference ! 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 --- 44,106 ---- boolean enqueue(Reference<? extends S> r) { return false; } } ! static final ReferenceQueue<Object> NULL = new Null<>(); ! static final ReferenceQueue<Object> ENQUEUED = new Null<>(); ! static private class Lock { } ! private final Lock lock = new Lock(); ! private volatile int waiters; ! @SuppressWarnings("unused") ! private volatile Reference<? extends T> head; // we assign using Unsafe CAS boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ ! ReferenceQueue<?> queue; ! do { ! // Check that this reference hasn't already been // enqueued (and even then removed) ! queue = r.queue; if ((queue == NULL) || (queue == ENQUEUED)) { return false; } + } while (!r.casQueue(queue, ENQUEUED)); assert queue == this; ! Reference<? extends T> h; ! do { ! h = head; ! r.next = (h == null) ? r : h; ! } while (!casHead(h, r)); ! ! if (waiters > 0) { ! synchronized (lock) { ! if (waiters > 0) { lock.notifyAll(); } } + } + return true; + } ! private Reference<? extends T> reallyPoll() { ! Reference<? extends T> r; ! while ((r = head) != null) { ! @SuppressWarnings("unchecked") // due to cast to raw type ! Reference<? extends T> nh = (r.next == r) ! ? null : (Reference) r.next; ! if (casHead(r, nh)) { ! r.lazySetQueue(NULL); ! UNSAFE.storeFence(); r.next = r; if (r instanceof FinalReference) { sun.misc.VM.addFinalRefCount(-1); } ! break; } ! } ! return r; } /** * 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
*** 100,115 **** * * @return A reference object, if one was immediately available, * otherwise <code>null</code> */ public Reference<? extends T> poll() { - if (head == null) - return null; - synchronized (lock) { return reallyPoll(); } - } /** * Removes the next reference object in this queue, blocking until either * one becomes available or the given timeout period expires. * --- 108,119 ----
*** 133,156 **** throws IllegalArgumentException, InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("Negative timeout value"); } - synchronized (lock) { Reference<? extends T> r = reallyPoll(); if (r != null) return r; ! long start = (timeout == 0) ? 0 : System.nanoTime(); for (;;) { ! lock.wait(timeout); ! r = reallyPoll(); if (r != null) return r; ! if (timeout != 0) { ! long end = System.nanoTime(); ! timeout -= (end - start) / 1000_000; ! if (timeout <= 0) return null; ! start = end; } } } } /** --- 137,171 ---- throws IllegalArgumentException, InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("Negative timeout value"); } Reference<? extends T> r = reallyPoll(); if (r != null) return r; ! return reallyRemove(timeout); ! } ! ! private Reference<? extends T> reallyRemove(long timeout) throws InterruptedException { ! long deadline = (timeout == 0) ! ? 0 : System.nanoTime() + timeout * 1000_000L; ! synchronized (lock) { ! int w = waiters; ! waiters = w + 1; ! try { for (;;) { ! Reference<? extends T> r = reallyPoll(); if (r != null) return r; ! if (timeout == 0) { ! lock.wait(0); ! } else { ! long timeoutNanos = deadline - System.nanoTime(); ! if (timeoutNanos <= 0) return null; ! lock.wait(timeoutNanos / 1000_000L, (int)(timeoutNanos % 1000_000L)); ! } } + } finally { + waiters = w; } } } /**
*** 162,167 **** --- 177,200 ---- */ public Reference<? extends T> remove() throws InterruptedException { return remove(0); } + // Unsafe machinery + + private boolean casHead(Reference<?> cmp, Reference<? extends T> val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + private static final sun.misc.Unsafe UNSAFE; + private static final long headOffset; + + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class<ReferenceQueue> rqc = ReferenceQueue.class; + headOffset = UNSAFE.objectFieldOffset(rqc.getDeclaredField("head")); + } catch (Exception e) { + throw new Error(e); + } + } }
< prev index next >