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.23 by jsr166, Thu Jul 23 23:07:57 2009 UTC vs.
Revision 1.30 by jsr166, Mon Jul 27 03:22:39 2009 UTC

# Line 5 | Line 5
5   */
6  
7   package jsr166y;
8 +
9   import java.util.concurrent.*;
10 < import java.util.concurrent.locks.*;
11 < import java.util.concurrent.atomic.*;
12 < import java.util.*;
13 < import java.io.*;
14 < import sun.misc.Unsafe;
15 < import java.lang.reflect.*;
10 >
11 > import java.util.AbstractQueue;
12 > import java.util.Collection;
13 > import java.util.Iterator;
14 > import java.util.NoSuchElementException;
15 > import java.util.concurrent.locks.LockSupport;
16 > import java.util.concurrent.atomic.AtomicReference;
17 > import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
18  
19   /**
20   * An unbounded {@linkplain TransferQueue} based on linked nodes.
# Line 102 | Line 105 | public class LinkedTransferQueue<E> exte
105       * garbage retention. Similarly, setting the next field to this is
106       * used as sentinel that node is off list.
107       */
108 <    static final class QNode extends AtomicReference<Object> {
109 <        volatile QNode next;
108 >    static final class Node<E> extends AtomicReference<Object> {
109 >        volatile Node<E> next;
110          volatile Thread waiter;       // to control park/unpark
111          final boolean isData;
112 <        QNode(Object item, boolean isData) {
112 >
113 >        Node(E item, boolean isData) {
114              super(item);
115              this.isData = isData;
116          }
117  
118 <        static final AtomicReferenceFieldUpdater<QNode, QNode>
118 >        @SuppressWarnings("rawtypes")
119 >        static final AtomicReferenceFieldUpdater<Node, Node>
120              nextUpdater = AtomicReferenceFieldUpdater.newUpdater
121 <            (QNode.class, QNode.class, "next");
121 >            (Node.class, Node.class, "next");
122  
123 <        final boolean casNext(QNode cmp, QNode val) {
123 >        final boolean casNext(Node<E> cmp, Node<E> val) {
124              return nextUpdater.compareAndSet(this, cmp, val);
125          }
126  
# Line 123 | Line 128 | public class LinkedTransferQueue<E> exte
128              nextUpdater.lazySet(this, this);
129          }
130  
131 +        private static final long serialVersionUID = -3375979862319811754L;
132      }
133  
134      /**
# Line 134 | Line 140 | public class LinkedTransferQueue<E> exte
140          // enough padding for 64bytes with 4byte refs
141          Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe;
142          PaddedAtomicReference(T r) { super(r); }
143 +        private static final long serialVersionUID = 8170090609809740854L;
144      }
145  
146  
147      /** head of the queue */
148 <    private transient final PaddedAtomicReference<QNode> head;
148 >    private transient final PaddedAtomicReference<Node<E>> head;
149  
150      /** tail of the queue */
151 <    private transient final PaddedAtomicReference<QNode> tail;
151 >    private transient final PaddedAtomicReference<Node<E>> tail;
152  
153      /**
154       * Reference to a cancelled node that might not yet have been
155       * unlinked from queue because it was the last inserted node
156       * when it cancelled.
157       */
158 <    private transient final PaddedAtomicReference<QNode> cleanMe;
158 >    private transient final PaddedAtomicReference<Node<E>> cleanMe;
159  
160      /**
161       * Tries to cas nh as new head; if successful, unlink
162       * old head's next node to avoid garbage retention.
163       */
164 <    private boolean advanceHead(QNode h, QNode nh) {
164 >    private boolean advanceHead(Node<E> h, Node<E> nh) {
165          if (h == head.get() && head.compareAndSet(h, nh)) {
166              h.clearNext(); // forget old next
167              return true;
# Line 172 | Line 179 | public class LinkedTransferQueue<E> exte
179       * @param nanos timeout in nanosecs, used only if mode is TIMEOUT
180       * @return an item, or null on failure
181       */
182 <    private Object xfer(Object e, int mode, long nanos) {
182 >    private E xfer(E e, int mode, long nanos) {
183          boolean isData = (e != null);
184 <        QNode s = null;
185 <        final PaddedAtomicReference<QNode> head = this.head;
186 <        final PaddedAtomicReference<QNode> tail = this.tail;
184 >        Node<E> s = null;
185 >        final PaddedAtomicReference<Node<E>> head = this.head;
186 >        final PaddedAtomicReference<Node<E>> tail = this.tail;
187  
188          for (;;) {
189 <            QNode t = tail.get();
190 <            QNode h = head.get();
189 >            Node<E> t = tail.get();
190 >            Node<E> h = head.get();
191  
192              if (t != null && (t == h || t.isData == isData)) {
193                  if (s == null)
194 <                    s = new QNode(e, isData);
195 <                QNode last = t.next;
194 >                    s = new Node<E>(e, isData);
195 >                Node<E> last = t.next;
196                  if (last != null) {
197                      if (t == tail.get())
198                          tail.compareAndSet(t, last);
# Line 197 | Line 204 | public class LinkedTransferQueue<E> exte
204              }
205  
206              else if (h != null) {
207 <                QNode first = h.next;
207 >                Node<E> first = h.next;
208                  if (t == tail.get() && first != null &&
209                      advanceHead(h, first)) {
210                      Object x = first.get();
211                      if (x != first && first.compareAndSet(x, e)) {
212                          LockSupport.unpark(first.waiter);
213 <                        return isData ? e : x;
213 >                        return isData ? e : (E) x;
214                      }
215                  }
216              }
# Line 215 | Line 222 | public class LinkedTransferQueue<E> exte
222       * Version of xfer for poll() and tryTransfer, which
223       * simplifies control paths both here and in xfer.
224       */
225 <    private Object fulfill(Object e) {
225 >    private E fulfill(E e) {
226          boolean isData = (e != null);
227 <        final PaddedAtomicReference<QNode> head = this.head;
228 <        final PaddedAtomicReference<QNode> tail = this.tail;
227 >        final PaddedAtomicReference<Node<E>> head = this.head;
228 >        final PaddedAtomicReference<Node<E>> tail = this.tail;
229  
230          for (;;) {
231 <            QNode t = tail.get();
232 <            QNode h = head.get();
231 >            Node<E> t = tail.get();
232 >            Node<E> h = head.get();
233  
234              if (t != null && (t == h || t.isData == isData)) {
235 <                QNode last = t.next;
235 >                Node<E> last = t.next;
236                  if (t == tail.get()) {
237                      if (last != null)
238                          tail.compareAndSet(t, last);
# Line 234 | Line 241 | public class LinkedTransferQueue<E> exte
241                  }
242              }
243              else if (h != null) {
244 <                QNode first = h.next;
244 >                Node<E> first = h.next;
245                  if (t == tail.get() &&
246                      first != null &&
247                      advanceHead(h, first)) {
248                      Object x = first.get();
249                      if (x != first && first.compareAndSet(x, e)) {
250                          LockSupport.unpark(first.waiter);
251 <                        return isData ? e : x;
251 >                        return isData ? e : (E) x;
252                      }
253                  }
254              }
# Line 259 | Line 266 | public class LinkedTransferQueue<E> exte
266       * @param nanos timeout value
267       * @return matched item, or s if cancelled
268       */
269 <    private Object awaitFulfill(QNode pred, QNode s, Object e,
270 <                                int mode, long nanos) {
269 >    private E awaitFulfill(Node<E> pred, Node<E> s, E e,
270 >                           int mode, long nanos) {
271          if (mode == NOWAIT)
272              return null;
273  
# Line 279 | Line 286 | public class LinkedTransferQueue<E> exte
286                  }
287                  else if (x != null) {
288                      s.set(s);             // avoid garbage retention
289 <                    return x;
289 >                    return (E) x;
290                  }
291                  else
292                      return e;
# Line 294 | Line 301 | public class LinkedTransferQueue<E> exte
301                  }
302              }
303              if (spins < 0) {
304 <                QNode h = head.get(); // only spin if at head
304 >                Node<E> h = head.get(); // only spin if at head
305                  spins = ((h != null && h.next == s) ?
306                           ((mode == TIMEOUT) ?
307                            maxTimedSpins : maxUntimedSpins) : 0);
# Line 319 | Line 326 | public class LinkedTransferQueue<E> exte
326      /**
327       * Returns validated tail for use in cleaning methods.
328       */
329 <    private QNode getValidatedTail() {
329 >    private Node<E> getValidatedTail() {
330          for (;;) {
331 <            QNode h = head.get();
332 <            QNode first = h.next;
331 >            Node<E> h = head.get();
332 >            Node<E> first = h.next;
333              if (first != null && first.next == first) { // help advance
334                  advanceHead(h, first);
335                  continue;
336              }
337 <            QNode t = tail.get();
338 <            QNode last = t.next;
337 >            Node<E> t = tail.get();
338 >            Node<E> last = t.next;
339              if (t == tail.get()) {
340                  if (last != null)
341                      tail.compareAndSet(t, last); // help advance
# Line 344 | Line 351 | public class LinkedTransferQueue<E> exte
351       * @param pred predecessor of cancelled node
352       * @param s the cancelled node
353       */
354 <    private void clean(QNode pred, QNode s) {
354 >    private void clean(Node<E> pred, Node<E> s) {
355          Thread w = s.waiter;
356          if (w != null) {             // Wake up thread
357              s.waiter = null;
# Line 364 | Line 371 | public class LinkedTransferQueue<E> exte
371           * processed, so this always terminates.
372           */
373          while (pred.next == s) {
374 <            QNode oldpred = reclean();  // First, help get rid of cleanMe
375 <            QNode t = getValidatedTail();
374 >            Node<E> oldpred = reclean();  // First, help get rid of cleanMe
375 >            Node<E> t = getValidatedTail();
376              if (s != t) {               // If not tail, try to unsplice
377 <                QNode sn = s.next;      // s.next == s means s already off list
377 >                Node<E> sn = s.next;      // s.next == s means s already off list
378                  if (sn == s || pred.casNext(s, sn))
379                      break;
380              }
# Line 383 | Line 390 | public class LinkedTransferQueue<E> exte
390       *
391       * @return current cleanMe node (or null)
392       */
393 <    private QNode reclean() {
393 >    private Node<E> reclean() {
394          /*
395           * cleanMe is, or at one time was, predecessor of cancelled
396           * node s that was the tail so could not be unspliced.  If s
# Line 395 | Line 402 | public class LinkedTransferQueue<E> exte
402           * This can loop only due to contention on casNext or
403           * clearing cleanMe.
404           */
405 <        QNode pred;
405 >        Node<E> pred;
406          while ((pred = cleanMe.get()) != null) {
407 <            QNode t = getValidatedTail();
408 <            QNode s = pred.next;
407 >            Node<E> t = getValidatedTail();
408 >            Node<E> s = pred.next;
409              if (s != t) {
410 <                QNode sn;
410 >                Node<E> sn;
411                  if (s == null || s == pred || s.get() != s ||
412                      (sn = s.next) == s || pred.casNext(s, sn))
413                      cleanMe.compareAndSet(pred, null);
# Line 415 | Line 422 | public class LinkedTransferQueue<E> exte
422       * Creates an initially empty {@code LinkedTransferQueue}.
423       */
424      public LinkedTransferQueue() {
425 <        QNode dummy = new QNode(null, false);
426 <        head = new PaddedAtomicReference<QNode>(dummy);
427 <        tail = new PaddedAtomicReference<QNode>(dummy);
428 <        cleanMe = new PaddedAtomicReference<QNode>(null);
425 >        Node<E> dummy = new Node<E>(null, false);
426 >        head = new PaddedAtomicReference<Node<E>>(dummy);
427 >        tail = new PaddedAtomicReference<Node<E>>(dummy);
428 >        cleanMe = new PaddedAtomicReference<Node<E>>(null);
429      }
430  
431      /**
# Line 435 | Line 442 | public class LinkedTransferQueue<E> exte
442          addAll(c);
443      }
444  
445 +    /**
446 +     * @throws InterruptedException {@inheritDoc}
447 +     * @throws NullPointerException {@inheritDoc}
448 +     */
449      public void put(E e) throws InterruptedException {
450          if (e == null) throw new NullPointerException();
451          if (Thread.interrupted()) throw new InterruptedException();
452          xfer(e, NOWAIT, 0);
453      }
454  
455 +    /**
456 +     * @throws InterruptedException {@inheritDoc}
457 +     * @throws NullPointerException {@inheritDoc}
458 +     */
459      public boolean offer(E e, long timeout, TimeUnit unit)
460          throws InterruptedException {
461          if (e == null) throw new NullPointerException();
# Line 449 | Line 464 | public class LinkedTransferQueue<E> exte
464          return true;
465      }
466  
467 +    /**
468 +     * @throws NullPointerException {@inheritDoc}
469 +     */
470      public boolean offer(E e) {
471          if (e == null) throw new NullPointerException();
472          xfer(e, NOWAIT, 0);
473          return true;
474      }
475  
476 +    /**
477 +     * @throws NullPointerException {@inheritDoc}
478 +     */
479      public boolean add(E e) {
480          if (e == null) throw new NullPointerException();
481          xfer(e, NOWAIT, 0);
482          return true;
483      }
484  
485 +    /**
486 +     * @throws InterruptedException {@inheritDoc}
487 +     * @throws NullPointerException {@inheritDoc}
488 +     */
489      public void transfer(E e) throws InterruptedException {
490          if (e == null) throw new NullPointerException();
491          if (xfer(e, WAIT, 0) == null) {
# Line 469 | Line 494 | public class LinkedTransferQueue<E> exte
494          }
495      }
496  
497 +    /**
498 +     * @throws InterruptedException {@inheritDoc}
499 +     * @throws NullPointerException {@inheritDoc}
500 +     */
501      public boolean tryTransfer(E e, long timeout, TimeUnit unit)
502          throws InterruptedException {
503          if (e == null) throw new NullPointerException();
# Line 479 | Line 508 | public class LinkedTransferQueue<E> exte
508          throw new InterruptedException();
509      }
510  
511 +    /**
512 +     * @throws NullPointerException {@inheritDoc}
513 +     */
514      public boolean tryTransfer(E e) {
515          if (e == null) throw new NullPointerException();
516          return fulfill(e) != null;
517      }
518  
519 +    /**
520 +     * @throws InterruptedException {@inheritDoc}
521 +     */
522      public E take() throws InterruptedException {
523          Object e = xfer(null, WAIT, 0);
524          if (e != null)
# Line 492 | Line 527 | public class LinkedTransferQueue<E> exte
527          throw new InterruptedException();
528      }
529  
530 +    /**
531 +     * @throws InterruptedException {@inheritDoc}
532 +     */
533      public E poll(long timeout, TimeUnit unit) throws InterruptedException {
534          Object e = xfer(null, TIMEOUT, unit.toNanos(timeout));
535          if (e != null || !Thread.interrupted())
# Line 500 | Line 538 | public class LinkedTransferQueue<E> exte
538      }
539  
540      public E poll() {
541 <        return (E) fulfill(null);
541 >        return fulfill(null);
542      }
543  
544 +    /**
545 +     * @throws NullPointerException     {@inheritDoc}
546 +     * @throws IllegalArgumentException {@inheritDoc}
547 +     */
548      public int drainTo(Collection<? super E> c) {
549          if (c == null)
550              throw new NullPointerException();
# Line 517 | Line 559 | public class LinkedTransferQueue<E> exte
559          return n;
560      }
561  
562 +    /**
563 +     * @throws NullPointerException     {@inheritDoc}
564 +     * @throws IllegalArgumentException {@inheritDoc}
565 +     */
566      public int drainTo(Collection<? super E> c, int maxElements) {
567          if (c == null)
568              throw new NullPointerException();
# Line 536 | Line 582 | public class LinkedTransferQueue<E> exte
582      /**
583       * Returns head after performing any outstanding helping steps.
584       */
585 <    private QNode traversalHead() {
585 >    private Node<E> traversalHead() {
586          for (;;) {
587 <            QNode t = tail.get();
588 <            QNode h = head.get();
587 >            Node<E> t = tail.get();
588 >            Node<E> h = head.get();
589              if (h != null && t != null) {
590 <                QNode last = t.next;
591 <                QNode first = h.next;
590 >                Node<E> last = t.next;
591 >                Node<E> first = h.next;
592                  if (t == tail.get()) {
593                      if (last != null)
594                          tail.compareAndSet(t, last);
# Line 574 | Line 620 | public class LinkedTransferQueue<E> exte
620       * if subsequently removed.
621       */
622      class Itr implements Iterator<E> {
623 <        QNode next;        // node to return next
624 <        QNode pnext;       // predecessor of next
625 <        QNode snext;       // successor of next
626 <        QNode curr;        // last returned node, for remove()
627 <        QNode pcurr;       // predecessor of curr, for remove()
623 >        Node<E> next;        // node to return next
624 >        Node<E> pnext;       // predecessor of next
625 >        Node<E> snext;       // successor of next
626 >        Node<E> curr;        // last returned node, for remove()
627 >        Node<E> pcurr;       // predecessor of curr, for remove()
628          E nextItem;        // Cache of next item, once committed to in next
629  
630          Itr() {
# Line 590 | Line 636 | public class LinkedTransferQueue<E> exte
636           */
637          void findNext() {
638              for (;;) {
639 <                QNode pred = pnext;
640 <                QNode q = next;
639 >                Node<E> pred = pnext;
640 >                Node<E> q = next;
641                  if (pred == null || pred == q) {
642                      pred = traversalHead();
643                      q = pred.next;
# Line 601 | Line 647 | public class LinkedTransferQueue<E> exte
647                      return;
648                  }
649                  Object x = q.get();
650 <                QNode s = q.next;
650 >                Node<E> s = q.next;
651                  if (x != null && q != x && q != s) {
652                      nextItem = (E) x;
653                      snext = s;
# Line 630 | Line 676 | public class LinkedTransferQueue<E> exte
676          }
677  
678          public void remove() {
679 <            QNode p = curr;
679 >            Node<E> p = curr;
680              if (p == null)
681                  throw new IllegalStateException();
682              Object x = p.get();
# Line 641 | Line 687 | public class LinkedTransferQueue<E> exte
687  
688      public E peek() {
689          for (;;) {
690 <            QNode h = traversalHead();
691 <            QNode p = h.next;
690 >            Node<E> h = traversalHead();
691 >            Node<E> p = h.next;
692              if (p == null)
693                  return null;
694              Object x = p.get();
# Line 657 | Line 703 | public class LinkedTransferQueue<E> exte
703  
704      public boolean isEmpty() {
705          for (;;) {
706 <            QNode h = traversalHead();
707 <            QNode p = h.next;
706 >            Node<E> h = traversalHead();
707 >            Node<E> p = h.next;
708              if (p == null)
709                  return true;
710              Object x = p.get();
# Line 673 | Line 719 | public class LinkedTransferQueue<E> exte
719  
720      public boolean hasWaitingConsumer() {
721          for (;;) {
722 <            QNode h = traversalHead();
723 <            QNode p = h.next;
722 >            Node<E> h = traversalHead();
723 >            Node<E> p = h.next;
724              if (p == null)
725                  return false;
726              Object x = p.get();
# Line 697 | Line 743 | public class LinkedTransferQueue<E> exte
743       */
744      public int size() {
745          int count = 0;
746 <        QNode h = traversalHead();
747 <        for (QNode p = h.next; p != null && p.isData; p = p.next) {
746 >        Node<E> h = traversalHead();
747 >        for (Node<E> p = h.next; p != null && p.isData; p = p.next) {
748              Object x = p.get();
749              if (x != null && x != p) {
750                  if (++count == Integer.MAX_VALUE) // saturated
# Line 710 | Line 756 | public class LinkedTransferQueue<E> exte
756  
757      public int getWaitingConsumerCount() {
758          int count = 0;
759 <        QNode h = traversalHead();
760 <        for (QNode p = h.next; p != null && !p.isData; p = p.next) {
759 >        Node<E> h = traversalHead();
760 >        for (Node<E> p = h.next; p != null && !p.isData; p = p.next) {
761              if (p.get() == null) {
762                  if (++count == Integer.MAX_VALUE)
763                      break;
# Line 728 | Line 774 | public class LinkedTransferQueue<E> exte
774          if (o == null)
775              return false;
776          for (;;) {
777 <            QNode pred = traversalHead();
777 >            Node<E> pred = traversalHead();
778              for (;;) {
779 <                QNode q = pred.next;
779 >                Node<E> q = pred.next;
780                  if (q == null || !q.isData)
781                      return false;
782                  if (q == pred) // restart
# Line 773 | Line 819 | public class LinkedTransferQueue<E> exte
819          s.defaultReadObject();
820          resetHeadAndTail();
821          for (;;) {
822 <            E item = (E) s.readObject();
822 >            @SuppressWarnings("unchecked") E item = (E) s.readObject();
823              if (item == null)
824                  break;
825              else
# Line 781 | Line 827 | public class LinkedTransferQueue<E> exte
827          }
828      }
829  
784
830      // Support for resetting head/tail while deserializing
831      private void resetHeadAndTail() {
832 <        QNode dummy = new QNode(null, false);
832 >        Node<E> dummy = new Node<E>(null, false);
833          UNSAFE.putObjectVolatile(this, headOffset,
834 <                                  new PaddedAtomicReference<QNode>(dummy));
834 >                                 new PaddedAtomicReference<Node<E>>(dummy));
835          UNSAFE.putObjectVolatile(this, tailOffset,
836 <                                  new PaddedAtomicReference<QNode>(dummy));
836 >                                 new PaddedAtomicReference<Node<E>>(dummy));
837          UNSAFE.putObjectVolatile(this, cleanMeOffset,
838 <                                  new PaddedAtomicReference<QNode>(null));
838 >                                 new PaddedAtomicReference<Node<E>>(null));
839      }
840  
841 <    // Temporary Unsafe mechanics for preliminary release
842 <    private static Unsafe getUnsafe() throws Throwable {
841 >    // Unsafe mechanics
842 >
843 >    private static final sun.misc.Unsafe UNSAFE = getUnsafe();
844 >    private static final long headOffset =
845 >        objectFieldOffset("head", LinkedTransferQueue.class);
846 >    private static final long tailOffset =
847 >        objectFieldOffset("tail", LinkedTransferQueue.class);
848 >    private static final long cleanMeOffset =
849 >        objectFieldOffset("cleanMe", LinkedTransferQueue.class);
850 >
851 >    private static long objectFieldOffset(String field, Class<?> klazz) {
852 >        try {
853 >            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
854 >        } catch (NoSuchFieldException e) {
855 >            // Convert Exception to corresponding Error
856 >            NoSuchFieldError error = new NoSuchFieldError(field);
857 >            error.initCause(e);
858 >            throw error;
859 >        }
860 >    }
861 >
862 >    /**
863 >     * Returns a sun.misc.Unsafe.  Suitable for use in a 3rd party package.
864 >     * Replace with a simple call to Unsafe.getUnsafe when integrating
865 >     * into a jdk.
866 >     *
867 >     * @return a sun.misc.Unsafe
868 >     */
869 >    private static sun.misc.Unsafe getUnsafe() {
870          try {
871 <            return Unsafe.getUnsafe();
871 >            return sun.misc.Unsafe.getUnsafe();
872          } catch (SecurityException se) {
873              try {
874                  return java.security.AccessController.doPrivileged
875 <                    (new java.security.PrivilegedExceptionAction<Unsafe>() {
876 <                        public Unsafe run() throws Exception {
877 <                            return getUnsafePrivileged();
875 >                    (new java.security
876 >                     .PrivilegedExceptionAction<sun.misc.Unsafe>() {
877 >                        public sun.misc.Unsafe run() throws Exception {
878 >                            java.lang.reflect.Field f = sun.misc
879 >                                .Unsafe.class.getDeclaredField("theUnsafe");
880 >                            f.setAccessible(true);
881 >                            return (sun.misc.Unsafe) f.get(null);
882                          }});
883              } catch (java.security.PrivilegedActionException e) {
884 <                throw e.getCause();
884 >                throw new RuntimeException("Could not initialize intrinsics",
885 >                                           e.getCause());
886              }
887          }
888      }
812
813    private static Unsafe getUnsafePrivileged()
814            throws NoSuchFieldException, IllegalAccessException {
815        Field f = Unsafe.class.getDeclaredField("theUnsafe");
816        f.setAccessible(true);
817        return (Unsafe) f.get(null);
818    }
819
820    private static long fieldOffset(String fieldName)
821            throws NoSuchFieldException {
822        return UNSAFE.objectFieldOffset
823            (LinkedTransferQueue.class.getDeclaredField(fieldName));
824    }
825
826    private static final Unsafe UNSAFE;
827    private static final long headOffset;
828    private static final long tailOffset;
829    private static final long cleanMeOffset;
830    static {
831        try {
832            UNSAFE = getUnsafe();
833            headOffset = fieldOffset("head");
834            tailOffset = fieldOffset("tail");
835            cleanMeOffset = fieldOffset("cleanMe");
836        } catch (Throwable e) {
837            throw new RuntimeException("Could not initialize intrinsics", e);
838        }
839    }
840
889   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines