📄 abstractqueuedlongsynchronizer.java
字号:
* * <p>In this implementation, this operation normally returns in * constant time, but may iterate upon contention if other threads are * concurrently modifying the queue. * * @return the first (longest-waiting) thread in the queue, or * {@code null} if no threads are currently queued */ public final Thread getFirstQueuedThread() { // handle only fast path, else relay return (head == tail)? null : fullGetFirstQueuedThread(); } /** * Version of getFirstQueuedThread called when fastpath fails */ private Thread fullGetFirstQueuedThread() { /* * The first node is normally h.next. Try to get its * thread field, ensuring consistent reads: If thread * field is nulled out or s.prev is no longer head, then * some other thread(s) concurrently performed setHead in * between some of our reads. We try this twice before * resorting to traversal. */ Node h, s; Thread st; if (((h = head) != null && (s = h.next) != null && s.prev == head && (st = s.thread) != null) || ((h = head) != null && (s = h.next) != null && s.prev == head && (st = s.thread) != null)) return st; /* * Head's next field might not have been set yet, or may have * been unset after setHead. So we must check to see if tail * is actually first node. If not, we continue on, safely * traversing from tail back to head to find first, * guaranteeing termination. */ Node t = tail; Thread firstThread = null; while (t != null && t != head) { Thread tt = t.thread; if (tt != null) firstThread = tt; t = t.prev; } return firstThread; } /** * Returns true if the given thread is currently queued. * * <p>This implementation traverses the queue to determine * presence of the given thread. * * @param thread the thread * @return {@code true} if the given thread is on the queue * @throws NullPointerException if the thread is null */ public final boolean isQueued(Thread thread) { if (thread == null) throw new NullPointerException(); for (Node p = tail; p != null; p = p.prev) if (p.thread == thread) return true; return false; } /** * Return {@code true} if the apparent first queued thread, if one * exists, is not waiting in exclusive mode. Used only as a heuristic * in ReentrantReadWriteLock. */ final boolean apparentlyFirstQueuedIsExclusive() { Node h, s; return ((h = head) != null && (s = h.next) != null && s.nextWaiter != Node.SHARED); } /** * Return {@code true} if the queue is empty or if the given thread * is at the head of the queue. This is reliable only if * <tt>current</tt> is actually Thread.currentThread() of caller. */ final boolean isFirst(Thread current) { Node h, s; return ((h = head) == null || ((s = h.next) != null && s.thread == current) || fullIsFirst(current)); } final boolean fullIsFirst(Thread current) { // same idea as fullGetFirstQueuedThread Node h, s; Thread firstThread = null; if (((h = head) != null && (s = h.next) != null && s.prev == head && (firstThread = s.thread) != null)) return firstThread == current; Node t = tail; while (t != null && t != head) { Thread tt = t.thread; if (tt != null) firstThread = tt; t = t.prev; } return firstThread == current || firstThread == null; } // Instrumentation and monitoring methods /** * Returns an estimate of the number of threads waiting to * acquire. The value is only an estimate because the number of * threads may change dynamically while this method traverses * internal data structures. This method is designed for use in * monitoring system state, not for synchronization * control. * * @return the estimated number of threads waiting to acquire */ public final int getQueueLength() { int n = 0; for (Node p = tail; p != null; p = p.prev) { if (p.thread != null) ++n; } return n; } /** * Returns a collection containing threads that may be waiting to * acquire. Because the actual set of threads may change * dynamically while constructing this result, the returned * collection is only a best-effort estimate. The elements of the * returned collection are in no particular order. This method is * designed to facilitate construction of subclasses that provide * more extensive monitoring facilities. * * @return the collection of threads */ public final Collection<Thread> getQueuedThreads() { ArrayList<Thread> list = new ArrayList<Thread>(); for (Node p = tail; p != null; p = p.prev) { Thread t = p.thread; if (t != null) list.add(t); } return list; } /** * Returns a collection containing threads that may be waiting to * acquire in exclusive mode. This has the same properties * as {@link #getQueuedThreads} except that it only returns * those threads waiting due to an exclusive acquire. * * @return the collection of threads */ public final Collection<Thread> getExclusiveQueuedThreads() { ArrayList<Thread> list = new ArrayList<Thread>(); for (Node p = tail; p != null; p = p.prev) { if (!p.isShared()) { Thread t = p.thread; if (t != null) list.add(t); } } return list; } /** * Returns a collection containing threads that may be waiting to * acquire in shared mode. This has the same properties * as {@link #getQueuedThreads} except that it only returns * those threads waiting due to a shared acquire. * * @return the collection of threads */ public final Collection<Thread> getSharedQueuedThreads() { ArrayList<Thread> list = new ArrayList<Thread>(); for (Node p = tail; p != null; p = p.prev) { if (p.isShared()) { Thread t = p.thread; if (t != null) list.add(t); } } return list; } /** * Returns a string identifying this synchronizer, as well as its state. * The state, in brackets, includes the String {@code "State ="} * followed by the current value of {@link #getState}, and either * {@code "nonempty"} or {@code "empty"} depending on whether the * queue is empty. * * @return a string identifying this synchronizer, as well as its state */ public String toString() { long s = getState(); String q = hasQueuedThreads()? "non" : ""; return super.toString() + "[State = " + s + ", " + q + "empty queue]"; } // Internal support methods for Conditions /** * Returns true if a node, always one that was initially placed on * a condition queue, is now waiting to reacquire on sync queue. * @param node the node * @return true if is reacquiring */ final boolean isOnSyncQueue(Node node) { if (node.waitStatus == Node.CONDITION || node.prev == null) return false; if (node.next != null) // If has successor, it must be on queue return true; /* * node.prev can be non-null, but not yet on queue because * the CAS to place it on queue can fail. So we have to * traverse from tail to make sure it actually made it. It * will always be near the tail in calls to this method, and * unless the CAS failed (which is unlikely), it will be * there, so we hardly ever traverse much. */ return findNodeFromTail(node); } /** * Returns true if node is on sync queue by searching backwards from tail. * Called only when needed by isOnSyncQueue. * @return true if present */ private boolean findNodeFromTail(Node node) { Node t = tail; for (;;) { if (t == node) return true; if (t == null) return false; t = t.prev; } } /** * Transfers a node from a condition queue onto sync queue. * Returns true if successful. * @param node the node * @return true if successfully transferred (else the node was * cancelled before signal). */ final boolean transferForSignal(Node node) { /* * If cannot change waitStatus, the node has been cancelled. */ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; /* * Splice onto queue and try to set waitStatus of predecessor to * indicate that thread is (probably) waiting. If cancelled or * attempt to set waitStatus fails, wake up to resync (in which * case the waitStatus can be transiently and harmlessly wrong). */ Node p = enq(node); int c = p.waitStatus; if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; } /** * Transfers node, if necessary, to sync queue after a cancelled * wait. Returns true if thread was cancelled before being * signalled. * @param current the waiting thread * @param node its node * @return true if cancelled before the node was signalled. */ final boolean transferAfterCancelledWait(Node node) { if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { enq(node); return true; } /* * If we lost out to a signal(), then we can't proceed * until it finishes its enq(). Cancelling during an * incomplete transfer is both rare and transient, so just * spin. */ while (!isOnSyncQueue(node)) Thread.yield(); return false; } /** * Invokes release with current state value; returns saved state. * Cancels node and throws exception on failure. * @param node the condition node for this wait * @return previous sync state */ final long fullyRelease(Node node) { try { long savedState = getState(); if (release(savedState)) return savedState; } catch (RuntimeException ex) { node.waitStatus = Node.CANCELLED; throw ex; } // reach here if release fails node.waitStatus = Node.CANCELLED; throw new IllegalMonitorStateException(); } // Instrumentation methods for conditions /** * Queries whether the given ConditionObject * uses this synchronizer as its lock. * * @param condition the condition * @return <tt>true</tt> if owned * @throws NullPointerException if the condition is null */ public final boolean owns(ConditionObject condition) { if (condition == null) throw new NullPointerException(); return condition.isOwnedBy(this); } /** * Queries whether any threads are waiting on the given condition * associated with this synchronizer. Note that because timeouts * and interrupts may occur at any time, a <tt>true</tt> return * does not guarantee that a future <tt>signal</tt> will awaken * any threads. This method is designed primarily for use in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -