ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166y/LinkedTransferQueue.java
(Generate patch)

Comparing jsr166/src/jsr166y/LinkedTransferQueue.java (file contents):
Revision 1.67 by dl, Sat Nov 14 20:27:18 2009 UTC vs.
Revision 1.77 by jsr166, Wed Sep 1 23:40:29 2010 UTC

# Line 15 | Line 15 | import java.util.Iterator;
15   import java.util.NoSuchElementException;
16   import java.util.Queue;
17   import java.util.concurrent.locks.LockSupport;
18 +
19   /**
20   * An unbounded {@link TransferQueue} based on linked nodes.
21   * This queue orders elements FIFO (first-in-first-out) with respect
# Line 321 | Line 322 | public class LinkedTransferQueue<E> exte
322       * situations in which we cannot guarantee to make node s
323       * unreachable in this way: (1) If s is the trailing node of list
324       * (i.e., with null next), then it is pinned as the target node
325 <     * for appends, so can only be removed later when other nodes are
325 >     * for appends, so can only be removed later after other nodes are
326       * appended. (2) We cannot necessarily unlink s given a
327       * predecessor node that is matched (including the case of being
328 <     * cancelled): the predecessor may already be already unspliced,
329 <     * in which case some previous reachable node may still point to
330 <     * s.  (For further explanation see Herlihy & Shavit "The Art of
328 >     * cancelled): the predecessor may already be unspliced, in which
329 >     * case some previous reachable node may still point to s.
330 >     * (For further explanation see Herlihy & Shavit "The Art of
331       * Multiprocessor Programming" chapter 9).  Although, in both
332       * cases, we can rule out the need for further action if either s
333       * or its predecessor are (or can be made to be) at, or fall off
# Line 343 | Line 344 | public class LinkedTransferQueue<E> exte
344       * When these cases arise, rather than always retraversing the
345       * entire list to find an actual predecessor to unlink (which
346       * won't help for case (1) anyway), we record a conservative
347 <     * estimate of possible unsplice failures (in "sweepVotes).  We
348 <     * trigger a full sweep when the estimate exceeds a threshold
349 <     * indicating the maximum number of estimated removal failures to
350 <     * tolerate before sweeping through, unlinking cancelled nodes
351 <     * that were not unlinked upon initial removal. We perform sweeps
352 <     * by the thread hitting threshold (rather than background threads
353 <     * or by spreading work to other threads) because in the main
354 <     * contexts in which removal occurs, the caller is already
355 <     * timed-out, cancelled, or performing a potentially O(n)
356 <     * operation (i.e., remove(x)), none of which are time-critical
357 <     * enough to warrant the overhead that alternatives would impose
358 <     * on other threads.
347 >     * estimate of possible unsplice failures (in "sweepVotes").
348 >     * We trigger a full sweep when the estimate exceeds a threshold
349 >     * ("SWEEP_THRESHOLD") indicating the maximum number of estimated
350 >     * removal failures to tolerate before sweeping through, unlinking
351 >     * cancelled nodes that were not unlinked upon initial removal.
352 >     * We perform sweeps by the thread hitting threshold (rather than
353 >     * background threads or by spreading work to other threads)
354 >     * because in the main contexts in which removal occurs, the
355 >     * caller is already timed-out, cancelled, or performing a
356 >     * potentially O(n) operation (e.g. remove(x)), none of which are
357 >     * time-critical enough to warrant the overhead that alternatives
358 >     * would impose on other threads.
359       *
360       * Because the sweepVotes estimate is conservative, and because
361       * nodes become unlinked "naturally" as they fall off the head of
362       * the queue, and because we allow votes to accumulate even while
363 <     * sweeps are in progress, there are typically signficantly fewer
363 >     * sweeps are in progress, there are typically significantly fewer
364       * such nodes than estimated.  Choice of a threshold value
365       * balances the likelihood of wasted effort and contention, versus
366       * providing a worst-case bound on retention of interior nodes in
# Line 422 | Line 423 | public class LinkedTransferQueue<E> exte
423          }
424  
425          final boolean casItem(Object cmp, Object val) {
426 <            assert cmp == null || cmp.getClass() != Node.class;
426 >            //            assert cmp == null || cmp.getClass() != Node.class;
427              return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
428          }
429  
430          /**
431 <         * Creates a new node. Uses relaxed write because item can only
432 <         * be seen if followed by CAS.
431 >         * Constructs a new node.  Uses relaxed write because item can
432 >         * only be seen after publication via casNext.
433           */
434          Node(Object item, boolean isData) {
435              UNSAFE.putObject(this, itemOffset, item); // relaxed write
# Line 446 | Line 447 | public class LinkedTransferQueue<E> exte
447          /**
448           * Sets item to self and waiter to null, to avoid garbage
449           * retention after matching or cancelling. Uses relaxed writes
450 <         * bacause order is already constrained in the only calling
450 >         * because order is already constrained in the only calling
451           * contexts: item is forgotten only after volatile/atomic
452           * mechanics that extract items.  Similarly, clearing waiter
453           * follows either CAS or return from park (if ever parked;
# Line 488 | Line 489 | public class LinkedTransferQueue<E> exte
489           * Tries to artificially match a data node -- used by remove.
490           */
491          final boolean tryMatchData() {
492 <            assert isData;
492 >            //            assert isData;
493              Object x = item;
494              if (x != null && x != this && casItem(x, null)) {
495                  LockSupport.unpark(waiter);
# Line 541 | Line 542 | public class LinkedTransferQueue<E> exte
542  
543      @SuppressWarnings("unchecked")
544      static <E> E cast(Object item) {
545 <        assert item == null || item.getClass() != Node.class;
545 >        //        assert item == null || item.getClass() != Node.class;
546          return (E) item;
547      }
548  
# Line 656 | Line 657 | public class LinkedTransferQueue<E> exte
657          for (;;) {
658              Object item = s.item;
659              if (item != e) {                  // matched
660 <                assert item != s;
660 >                //                assert item != s;
661                  s.forgetContents();           // avoid garbage
662                  return this.<E>cast(item);
663              }
# Line 876 | Line 877 | public class LinkedTransferQueue<E> exte
877      }
878  
879      /**
880 <     * Unlink matched nodes encountered in a traversal from head
880 >     * Unlinks matched (typically cancelled) nodes encountered in a
881 >     * traversal from head.
882       */
883      private void sweep() {
884 <        Node p = head, s, n;
885 <        while (p != null && (s = p.next) != null && (n = s.next) != null) {
886 <            if (p == s || s == n)
887 <                p = head; // stale
886 <            else if (s.isMatched())
887 <                p.casNext(s, n);
888 <            else
884 >        for (Node p = head, s, n; p != null && (s = p.next) != null; ) {
885 >            if (p == s)                    // stale
886 >                p = head;
887 >            else if (!s.isMatched())
888                  p = s;
889 +            else if ((n = s.next) == null) // trailing node is pinned
890 +                break;
891 +            else
892 +                p.casNext(s, n);
893          }
894      }
895  
# Line 1124 | Line 1127 | public class LinkedTransferQueue<E> exte
1127       * @return {@code true} if this queue contains no elements
1128       */
1129      public boolean isEmpty() {
1130 <        return firstOfMode(true) == null;
1130 >        for (Node p = head; p != null; p = succ(p)) {
1131 >            if (!p.isMatched())
1132 >                return !p.isData;
1133 >        }
1134 >        return true;
1135      }
1136  
1137      public boolean hasWaitingConsumer() {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines