Ejemplo n.º 1
0
 /**
  * Tries to match node s to this node, if so, waking up thread. Fulfillers call tryMatch to
  * identify their waiters. Waiters block until they have been matched.
  *
  * @param s the node to match
  * @return true if successfully matched to s
  */
 boolean tryMatch(SNode s) {
   if (match == null && UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
     Thread w = waiter;
     if (w != null) { // waiters need at most one unpark
       waiter = null;
       LockSupport.unpark(w);
     }
     return true;
   }
   return match == s;
 }
Ejemplo n.º 2
0
    /** Puts or takes an item. */
    Object transfer(Object e, boolean timed, long nanos) {
      /* Basic algorithm is to loop trying to take either of
       * two actions:
       *
       * 1. If queue apparently empty or holding same-mode nodes,
       *    try to add node to queue of waiters, wait to be
       *    fulfilled (or cancelled) and return matching item.
       *
       * 2. If queue apparently contains waiting items, and this
       *    call is of complementary mode, try to fulfill by CAS'ing
       *    item field of waiting node and dequeuing it, and then
       *    returning matching item.
       *
       * In each case, along the way, check for and try to help
       * advance head and tail on behalf of other stalled/slow
       * threads.
       *
       * The loop starts off with a null check guarding against
       * seeing uninitialized head or tail values. This never
       * happens in current SynchronousQueue, but could if
       * callers held non-volatile/final ref to the
       * transferer. The check is here anyway because it places
       * null checks at top of loop, which is usually faster
       * than having them implicitly interspersed.
       */

      QNode s = null; // constructed/reused as needed
      boolean isData = (e != null);

      for (; ; ) {
        QNode t = tail;
        QNode h = head;
        if (t == null || h == null) // saw uninitialized value
        continue; // spin

        if (h == t || t.isData == isData) { // empty or same-mode
          QNode tn = t.next;
          if (t != tail) // inconsistent read
          continue;
          if (tn != null) { // lagging tail
            advanceTail(t, tn);
            continue;
          }
          if (timed && nanos <= 0) // can't wait
          return null;
          if (s == null) s = new QNode(e, isData);
          if (!t.casNext(null, s)) // failed to link in
          continue;

          advanceTail(t, s); // swing tail and wait
          Object x = awaitFulfill(s, e, timed, nanos);
          if (x == s) { // wait was cancelled
            clean(t, s);
            return null;
          }

          if (!s.isOffList()) { // not already unlinked
            advanceHead(t, s); // unlink if head
            if (x != null) // and forget fields
            s.item = s;
            s.waiter = null;
          }
          return (x != null) ? x : e;

        } else { // complementary-mode
          QNode m = h.next; // node to fulfill
          if (t != tail || m == null || h != head) continue; // inconsistent read

          Object x = m.item;
          if (isData == (x != null)
              || // m already fulfilled
              x == m
              || // m cancelled
              !m.casItem(x, e)) { // lost CAS
            advanceHead(h, m); // dequeue and retry
            continue;
          }

          advanceHead(h, m); // successfully fulfilled
          LockSupport.unpark(m.waiter);
          return (x != null) ? x : e;
        }
      }
    }