コード例 #1
0
  /**
   * Spins/yields/blocks until node s is matched or caller gives up.
   *
   * @param s the waiting node
   * @param pred the predecessor of s, or s itself if it has no predecessor, or null if unknown (the
   *     null case does not occur in any current calls but may in possible future extensions)
   * @param e the comparison value for checking match
   * @param timed if true, wait only until timeout elapses
   * @param nanos timeout in nanosecs, used only if timed is true
   * @return matched item, or e if unmatched on interrupt or timeout
   */
  private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) {
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    Thread w = Thread.currentThread();
    int spins = -1; // initialized after first item and cancel checks
    ThreadLocalRandom randomYields = null; // bound if needed

    for (; ; ) {
      Object item = s.item;
      if (item != e) { // matched
        // assert item != s;
        s.forgetContents(); // avoid garbage
        return LinkedTransferQueue.<E>cast(item);
      }
      if ((w.isInterrupted() || (timed && nanos <= 0)) && s.casItem(e, FORGOTTEN)) { // cancel
        unsplice(pred, s);
        return e;
      }

      if (spins < 0) { // establish spins at/near front
        if ((spins = spinsFor(pred, s.isData)) > 0) randomYields = ThreadLocalRandom.current();
      } else if (spins > 0) { // spin
        --spins;
        if (randomYields.nextInt(CHAINED_SPINS) == 0) Thread.yield(); // occasionally yield
      } else if (s.waiter == null) {
        s.waiter = w; // request unpark then recheck
      } else if (timed) {
        nanos = deadline - System.nanoTime();
        if (nanos > 0L) LockSupport.parkNanos(this, nanos);
      } else {
        LockSupport.park(this);
      }
    }
  }
コード例 #2
0
 /** Returns the item in the first unmatched node with isData; or null if none. Used by peek. */
 private E firstDataItem() {
   for (Node p = head; p != null; p = succ(p)) {
     Object item = p.item;
     if (p.isData) {
       if (item != null && item != FORGOTTEN) return LinkedTransferQueue.<E>cast(item);
     } else if (item == null) return null;
   }
   return null;
 }
コード例 #3
0
    /** Moves to next node after prev, or first node if prev null. */
    private void advance(Node prev) {
      /*
       * To track and avoid buildup of deleted nodes in the face
       * of calls to both Queue.remove and Itr.remove, we must
       * include variants of unsplice and sweep upon each
       * advance: Upon Itr.remove, we may need to catch up links
       * from lastPred, and upon other removes, we might need to
       * skip ahead from stale nodes and unsplice deleted ones
       * found while advancing.
       */

      Node r, b; // reset lastPred upon possible deletion of lastRet
      if ((r = lastRet) != null && !r.isMatched()) lastPred = r; // next lastPred is old lastRet
      else if ((b = lastPred) == null || b.isMatched()) lastPred = null; // at start of list
      else {
        Node s, n; // help with removal of lastPred.next
        while ((s = b.next) != null
            && s != UNLINKED
            && s.isMatched()
            && (n = s.next) != null
            && n != UNLINKED) b.casNext(s, n);
      }

      this.lastRet = prev;

      for (Node p = prev, s, n; ; ) {
        s = (p == null) ? head : p.next;
        if (s == null) break;
        else if (s == UNLINKED) {
          p = null;
          continue;
        }
        Object item = s.item;
        if (s.isData) {
          if (item != null && item != FORGOTTEN) {
            nextItem = LinkedTransferQueue.<E>cast(item);
            nextNode = s;
            return;
          }
        } else if (item == null) break;
        // assert s.isMatched();
        if (p == null) p = s;
        else if ((n = s.next) == null) break;
        else if (UNLINKED == n) p = null;
        else p.casNext(s, n);
      }
      nextNode = null;
      nextItem = null;
    }
コード例 #4
0
  /**
   * Implements all queuing methods. See above for explanation.
   *
   * @param e the item or null for take
   * @param haveData true if this is a put, else a take
   * @param how NOW, ASYNC, SYNC, or TIMED
   * @param nanos timeout in nanosecs, used only if mode is TIMED
   * @return an item if matched, else e
   * @throws NullPointerException if haveData mode but e is null
   */
  private E xfer(E e, boolean haveData, int how, long nanos) {
    if (haveData && (e == null)) throw new NullPointerException();
    Node s = null; // the node to append, if needed

    retry:
    for (; ; ) { // restart on append race

      for (Node h = head, p = h; p != null; ) { // find & match first node
        boolean isData = p.isData;
        Object item = p.item;
        if (item != FORGOTTEN && (item != null) == isData) { // unmatched
          if (isData == haveData) // can't match
          break;
          if (p.casItem(item, e)) { // match
            for (Node q = p; q != h; ) {
              Node n = q.next; // update by 2 unless singleton
              if (head == h && casHead(h, n == null ? q : n)) {
                h.forgetNext();
                break;
              } // advance and retry
              if ((h = head) == null || (q = h.next) == null || !q.isMatched())
                break; // unless slack < 2
            }
            LockSupport.unpark(p.waiter);
            return LinkedTransferQueue.<E>cast(item);
          }
        }
        Node n = p.next;
        p = (UNLINKED != n) ? n : (h = head); // Use head if p offlist
      }

      if (how != NOW) { // No matches available
        if (s == null) s = new Node(e, haveData);
        Node pred = tryAppend(s, haveData);
        if (pred == null) continue retry; // lost race vs opposite mode
        if (how != ASYNC) return awaitMatch(s, pred, e, (how == TIMED), nanos);
      }
      return e; // not waiting
    }
  }