ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166y/LinkedTransferQueue.java
Revision: 1.25
Committed: Fri Jul 24 23:48:26 2009 UTC (14 years, 9 months ago) by jsr166
Branch: MAIN
Changes since 1.24: +111 -112 lines
Log Message:
Unsafe mechanics; QNode => Node<E>

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/licenses/publicdomain
5 */
6
7 package jsr166y;
8 import java.util.concurrent.*;
9 import java.util.concurrent.locks.*;
10 import java.util.concurrent.atomic.*;
11 import java.util.*;
12 import java.io.*;
13
14 /**
15 * An unbounded {@linkplain TransferQueue} based on linked nodes.
16 * This queue orders elements FIFO (first-in-first-out) with respect
17 * to any given producer. The <em>head</em> of the queue is that
18 * element that has been on the queue the longest time for some
19 * producer. The <em>tail</em> of the queue is that element that has
20 * been on the queue the shortest time for some producer.
21 *
22 * <p>Beware that, unlike in most collections, the {@code size}
23 * method is <em>NOT</em> a constant-time operation. Because of the
24 * asynchronous nature of these queues, determining the current number
25 * of elements requires a traversal of the elements.
26 *
27 * <p>This class and its iterator implement all of the
28 * <em>optional</em> methods of the {@link Collection} and {@link
29 * Iterator} interfaces.
30 *
31 * <p>Memory consistency effects: As with other concurrent
32 * collections, actions in a thread prior to placing an object into a
33 * {@code LinkedTransferQueue}
34 * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
35 * actions subsequent to the access or removal of that element from
36 * the {@code LinkedTransferQueue} in another thread.
37 *
38 * <p>This class is a member of the
39 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
40 * Java Collections Framework</a>.
41 *
42 * @since 1.7
43 * @author Doug Lea
44 * @param <E> the type of elements held in this collection
45 */
46 public class LinkedTransferQueue<E> extends AbstractQueue<E>
47 implements TransferQueue<E>, java.io.Serializable {
48 private static final long serialVersionUID = -3223113410248163686L;
49
50 /*
51 * This class extends the approach used in FIFO-mode
52 * SynchronousQueues. See the internal documentation, as well as
53 * the PPoPP 2006 paper "Scalable Synchronous Queues" by Scherer,
54 * Lea & Scott
55 * (http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf)
56 *
57 * The main extension is to provide different Wait modes for the
58 * main "xfer" method that puts or takes items. These don't
59 * impact the basic dual-queue logic, but instead control whether
60 * or how threads block upon insertion of request or data nodes
61 * into the dual queue. It also uses slightly different
62 * conventions for tracking whether nodes are off-list or
63 * cancelled.
64 */
65
66 // Wait modes for xfer method
67 static final int NOWAIT = 0;
68 static final int TIMEOUT = 1;
69 static final int WAIT = 2;
70
71 /** The number of CPUs, for spin control */
72 static final int NCPUS = Runtime.getRuntime().availableProcessors();
73
74 /**
75 * The number of times to spin before blocking in timed waits.
76 * The value is empirically derived -- it works well across a
77 * variety of processors and OSes. Empirically, the best value
78 * seems not to vary with number of CPUs (beyond 2) so is just
79 * a constant.
80 */
81 static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
82
83 /**
84 * The number of times to spin before blocking in untimed waits.
85 * This is greater than timed value because untimed waits spin
86 * faster since they don't need to check times on each spin.
87 */
88 static final int maxUntimedSpins = maxTimedSpins * 16;
89
90 /**
91 * The number of nanoseconds for which it is faster to spin
92 * rather than to use timed park. A rough estimate suffices.
93 */
94 static final long spinForTimeoutThreshold = 1000L;
95
96 /**
97 * Node class for LinkedTransferQueue. Opportunistically
98 * subclasses from AtomicReference to represent item. Uses Object,
99 * not E, to allow setting item to "this" after use, to avoid
100 * garbage retention. Similarly, setting the next field to this is
101 * used as sentinel that node is off list.
102 */
103 static final class Node<E> extends AtomicReference<Object> {
104 volatile Node<E> next;
105 volatile Thread waiter; // to control park/unpark
106 final boolean isData;
107
108 Node(E item, boolean isData) {
109 super(item);
110 this.isData = isData;
111 }
112
113 @SuppressWarnings("rawtypes")
114 static final AtomicReferenceFieldUpdater<Node, Node>
115 nextUpdater = AtomicReferenceFieldUpdater.newUpdater
116 (Node.class, Node.class, "next");
117
118 final boolean casNext(Node<E> cmp, Node<E> val) {
119 return nextUpdater.compareAndSet(this, cmp, val);
120 }
121
122 final void clearNext() {
123 nextUpdater.lazySet(this, this);
124 }
125
126 private static final long serialVersionUID = -3375979862319811754L;
127 }
128
129 /**
130 * Padded version of AtomicReference used for head, tail and
131 * cleanMe, to alleviate contention across threads CASing one vs
132 * the other.
133 */
134 static final class PaddedAtomicReference<T> extends AtomicReference<T> {
135 // enough padding for 64bytes with 4byte refs
136 Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe;
137 PaddedAtomicReference(T r) { super(r); }
138 private static final long serialVersionUID = 8170090609809740854L;
139 }
140
141
142 /** head of the queue */
143 private transient final PaddedAtomicReference<Node<E>> head;
144
145 /** tail of the queue */
146 private transient final PaddedAtomicReference<Node<E>> tail;
147
148 /**
149 * Reference to a cancelled node that might not yet have been
150 * unlinked from queue because it was the last inserted node
151 * when it cancelled.
152 */
153 private transient final PaddedAtomicReference<Node<E>> cleanMe;
154
155 /**
156 * Tries to cas nh as new head; if successful, unlink
157 * old head's next node to avoid garbage retention.
158 */
159 private boolean advanceHead(Node<E> h, Node<E> nh) {
160 if (h == head.get() && head.compareAndSet(h, nh)) {
161 h.clearNext(); // forget old next
162 return true;
163 }
164 return false;
165 }
166
167 /**
168 * Puts or takes an item. Used for most queue operations (except
169 * poll() and tryTransfer()). See the similar code in
170 * SynchronousQueue for detailed explanation.
171 *
172 * @param e the item or if null, signifies that this is a take
173 * @param mode the wait mode: NOWAIT, TIMEOUT, WAIT
174 * @param nanos timeout in nanosecs, used only if mode is TIMEOUT
175 * @return an item, or null on failure
176 */
177 private E xfer(E e, int mode, long nanos) {
178 boolean isData = (e != null);
179 Node<E> s = null;
180 final PaddedAtomicReference<Node<E>> head = this.head;
181 final PaddedAtomicReference<Node<E>> tail = this.tail;
182
183 for (;;) {
184 Node<E> t = tail.get();
185 Node<E> h = head.get();
186
187 if (t != null && (t == h || t.isData == isData)) {
188 if (s == null)
189 s = new Node<E>(e, isData);
190 Node<E> last = t.next;
191 if (last != null) {
192 if (t == tail.get())
193 tail.compareAndSet(t, last);
194 }
195 else if (t.casNext(null, s)) {
196 tail.compareAndSet(t, s);
197 return awaitFulfill(t, s, e, mode, nanos);
198 }
199 }
200
201 else if (h != null) {
202 Node<E> first = h.next;
203 if (t == tail.get() && first != null &&
204 advanceHead(h, first)) {
205 Object x = first.get();
206 if (x != first && first.compareAndSet(x, e)) {
207 LockSupport.unpark(first.waiter);
208 return isData ? e : (E) x;
209 }
210 }
211 }
212 }
213 }
214
215
216 /**
217 * Version of xfer for poll() and tryTransfer, which
218 * simplifies control paths both here and in xfer.
219 */
220 private E fulfill(E e) {
221 boolean isData = (e != null);
222 final PaddedAtomicReference<Node<E>> head = this.head;
223 final PaddedAtomicReference<Node<E>> tail = this.tail;
224
225 for (;;) {
226 Node<E> t = tail.get();
227 Node<E> h = head.get();
228
229 if (t != null && (t == h || t.isData == isData)) {
230 Node<E> last = t.next;
231 if (t == tail.get()) {
232 if (last != null)
233 tail.compareAndSet(t, last);
234 else
235 return null;
236 }
237 }
238 else if (h != null) {
239 Node<E> first = h.next;
240 if (t == tail.get() &&
241 first != null &&
242 advanceHead(h, first)) {
243 Object x = first.get();
244 if (x != first && first.compareAndSet(x, e)) {
245 LockSupport.unpark(first.waiter);
246 return isData ? e : (E) x;
247 }
248 }
249 }
250 }
251 }
252
253 /**
254 * Spins/blocks until node s is fulfilled or caller gives up,
255 * depending on wait mode.
256 *
257 * @param pred the predecessor of waiting node
258 * @param s the waiting node
259 * @param e the comparison value for checking match
260 * @param mode mode
261 * @param nanos timeout value
262 * @return matched item, or s if cancelled
263 */
264 private E awaitFulfill(Node<E> pred, Node<E> s, E e,
265 int mode, long nanos) {
266 if (mode == NOWAIT)
267 return null;
268
269 long lastTime = (mode == TIMEOUT) ? System.nanoTime() : 0;
270 Thread w = Thread.currentThread();
271 int spins = -1; // set to desired spin count below
272 for (;;) {
273 if (w.isInterrupted())
274 s.compareAndSet(e, s);
275 Object x = s.get();
276 if (x != e) { // Node was matched or cancelled
277 advanceHead(pred, s); // unlink if head
278 if (x == s) { // was cancelled
279 clean(pred, s);
280 return null;
281 }
282 else if (x != null) {
283 s.set(s); // avoid garbage retention
284 return (E) x;
285 }
286 else
287 return e;
288 }
289 if (mode == TIMEOUT) {
290 long now = System.nanoTime();
291 nanos -= now - lastTime;
292 lastTime = now;
293 if (nanos <= 0) {
294 s.compareAndSet(e, s); // try to cancel
295 continue;
296 }
297 }
298 if (spins < 0) {
299 Node<E> h = head.get(); // only spin if at head
300 spins = ((h != null && h.next == s) ?
301 ((mode == TIMEOUT) ?
302 maxTimedSpins : maxUntimedSpins) : 0);
303 }
304 if (spins > 0)
305 --spins;
306 else if (s.waiter == null)
307 s.waiter = w;
308 else if (mode != TIMEOUT) {
309 LockSupport.park(this);
310 s.waiter = null;
311 spins = -1;
312 }
313 else if (nanos > spinForTimeoutThreshold) {
314 LockSupport.parkNanos(this, nanos);
315 s.waiter = null;
316 spins = -1;
317 }
318 }
319 }
320
321 /**
322 * Returns validated tail for use in cleaning methods.
323 */
324 private Node<E> getValidatedTail() {
325 for (;;) {
326 Node<E> h = head.get();
327 Node<E> first = h.next;
328 if (first != null && first.next == first) { // help advance
329 advanceHead(h, first);
330 continue;
331 }
332 Node<E> t = tail.get();
333 Node<E> last = t.next;
334 if (t == tail.get()) {
335 if (last != null)
336 tail.compareAndSet(t, last); // help advance
337 else
338 return t;
339 }
340 }
341 }
342
343 /**
344 * Gets rid of cancelled node s with original predecessor pred.
345 *
346 * @param pred predecessor of cancelled node
347 * @param s the cancelled node
348 */
349 private void clean(Node<E> pred, Node<E> s) {
350 Thread w = s.waiter;
351 if (w != null) { // Wake up thread
352 s.waiter = null;
353 if (w != Thread.currentThread())
354 LockSupport.unpark(w);
355 }
356
357 if (pred == null)
358 return;
359
360 /*
361 * At any given time, exactly one node on list cannot be
362 * deleted -- the last inserted node. To accommodate this, if
363 * we cannot delete s, we save its predecessor as "cleanMe",
364 * processing the previously saved version first. At least one
365 * of node s or the node previously saved can always be
366 * processed, so this always terminates.
367 */
368 while (pred.next == s) {
369 Node<E> oldpred = reclean(); // First, help get rid of cleanMe
370 Node<E> t = getValidatedTail();
371 if (s != t) { // If not tail, try to unsplice
372 Node<E> sn = s.next; // s.next == s means s already off list
373 if (sn == s || pred.casNext(s, sn))
374 break;
375 }
376 else if (oldpred == pred || // Already saved
377 (oldpred == null && cleanMe.compareAndSet(null, pred)))
378 break; // Postpone cleaning
379 }
380 }
381
382 /**
383 * Tries to unsplice the cancelled node held in cleanMe that was
384 * previously uncleanable because it was at tail.
385 *
386 * @return current cleanMe node (or null)
387 */
388 private Node<E> reclean() {
389 /*
390 * cleanMe is, or at one time was, predecessor of cancelled
391 * node s that was the tail so could not be unspliced. If s
392 * is no longer the tail, try to unsplice if necessary and
393 * make cleanMe slot available. This differs from similar
394 * code in clean() because we must check that pred still
395 * points to a cancelled node that must be unspliced -- if
396 * not, we can (must) clear cleanMe without unsplicing.
397 * This can loop only due to contention on casNext or
398 * clearing cleanMe.
399 */
400 Node<E> pred;
401 while ((pred = cleanMe.get()) != null) {
402 Node<E> t = getValidatedTail();
403 Node<E> s = pred.next;
404 if (s != t) {
405 Node<E> sn;
406 if (s == null || s == pred || s.get() != s ||
407 (sn = s.next) == s || pred.casNext(s, sn))
408 cleanMe.compareAndSet(pred, null);
409 }
410 else // s is still tail; cannot clean
411 break;
412 }
413 return pred;
414 }
415
416 /**
417 * Creates an initially empty {@code LinkedTransferQueue}.
418 */
419 public LinkedTransferQueue() {
420 Node<E> dummy = new Node<E>(null, false);
421 head = new PaddedAtomicReference<Node<E>>(dummy);
422 tail = new PaddedAtomicReference<Node<E>>(dummy);
423 cleanMe = new PaddedAtomicReference<Node<E>>(null);
424 }
425
426 /**
427 * Creates a {@code LinkedTransferQueue}
428 * initially containing the elements of the given collection,
429 * added in traversal order of the collection's iterator.
430 *
431 * @param c the collection of elements to initially contain
432 * @throws NullPointerException if the specified collection or any
433 * of its elements are null
434 */
435 public LinkedTransferQueue(Collection<? extends E> c) {
436 this();
437 addAll(c);
438 }
439
440 public void put(E e) throws InterruptedException {
441 if (e == null) throw new NullPointerException();
442 if (Thread.interrupted()) throw new InterruptedException();
443 xfer(e, NOWAIT, 0);
444 }
445
446 public boolean offer(E e, long timeout, TimeUnit unit)
447 throws InterruptedException {
448 if (e == null) throw new NullPointerException();
449 if (Thread.interrupted()) throw new InterruptedException();
450 xfer(e, NOWAIT, 0);
451 return true;
452 }
453
454 public boolean offer(E e) {
455 if (e == null) throw new NullPointerException();
456 xfer(e, NOWAIT, 0);
457 return true;
458 }
459
460 public boolean add(E e) {
461 if (e == null) throw new NullPointerException();
462 xfer(e, NOWAIT, 0);
463 return true;
464 }
465
466 public void transfer(E e) throws InterruptedException {
467 if (e == null) throw new NullPointerException();
468 if (xfer(e, WAIT, 0) == null) {
469 Thread.interrupted();
470 throw new InterruptedException();
471 }
472 }
473
474 public boolean tryTransfer(E e, long timeout, TimeUnit unit)
475 throws InterruptedException {
476 if (e == null) throw new NullPointerException();
477 if (xfer(e, TIMEOUT, unit.toNanos(timeout)) != null)
478 return true;
479 if (!Thread.interrupted())
480 return false;
481 throw new InterruptedException();
482 }
483
484 public boolean tryTransfer(E e) {
485 if (e == null) throw new NullPointerException();
486 return fulfill(e) != null;
487 }
488
489 public E take() throws InterruptedException {
490 Object e = xfer(null, WAIT, 0);
491 if (e != null)
492 return (E) e;
493 Thread.interrupted();
494 throw new InterruptedException();
495 }
496
497 public E poll(long timeout, TimeUnit unit) throws InterruptedException {
498 Object e = xfer(null, TIMEOUT, unit.toNanos(timeout));
499 if (e != null || !Thread.interrupted())
500 return (E) e;
501 throw new InterruptedException();
502 }
503
504 public E poll() {
505 return fulfill(null);
506 }
507
508 public int drainTo(Collection<? super E> c) {
509 if (c == null)
510 throw new NullPointerException();
511 if (c == this)
512 throw new IllegalArgumentException();
513 int n = 0;
514 E e;
515 while ( (e = poll()) != null) {
516 c.add(e);
517 ++n;
518 }
519 return n;
520 }
521
522 public int drainTo(Collection<? super E> c, int maxElements) {
523 if (c == null)
524 throw new NullPointerException();
525 if (c == this)
526 throw new IllegalArgumentException();
527 int n = 0;
528 E e;
529 while (n < maxElements && (e = poll()) != null) {
530 c.add(e);
531 ++n;
532 }
533 return n;
534 }
535
536 // Traversal-based methods
537
538 /**
539 * Returns head after performing any outstanding helping steps.
540 */
541 private Node<E> traversalHead() {
542 for (;;) {
543 Node<E> t = tail.get();
544 Node<E> h = head.get();
545 if (h != null && t != null) {
546 Node<E> last = t.next;
547 Node<E> first = h.next;
548 if (t == tail.get()) {
549 if (last != null)
550 tail.compareAndSet(t, last);
551 else if (first != null) {
552 Object x = first.get();
553 if (x == first)
554 advanceHead(h, first);
555 else
556 return h;
557 }
558 else
559 return h;
560 }
561 }
562 reclean();
563 }
564 }
565
566
567 public Iterator<E> iterator() {
568 return new Itr();
569 }
570
571 /**
572 * Iterators. Basic strategy is to traverse list, treating
573 * non-data (i.e., request) nodes as terminating list.
574 * Once a valid data node is found, the item is cached
575 * so that the next call to next() will return it even
576 * if subsequently removed.
577 */
578 class Itr implements Iterator<E> {
579 Node<E> next; // node to return next
580 Node<E> pnext; // predecessor of next
581 Node<E> snext; // successor of next
582 Node<E> curr; // last returned node, for remove()
583 Node<E> pcurr; // predecessor of curr, for remove()
584 E nextItem; // Cache of next item, once committed to in next
585
586 Itr() {
587 findNext();
588 }
589
590 /**
591 * Ensures next points to next valid node, or null if none.
592 */
593 void findNext() {
594 for (;;) {
595 Node<E> pred = pnext;
596 Node<E> q = next;
597 if (pred == null || pred == q) {
598 pred = traversalHead();
599 q = pred.next;
600 }
601 if (q == null || !q.isData) {
602 next = null;
603 return;
604 }
605 Object x = q.get();
606 Node<E> s = q.next;
607 if (x != null && q != x && q != s) {
608 nextItem = (E) x;
609 snext = s;
610 pnext = pred;
611 next = q;
612 return;
613 }
614 pnext = q;
615 next = s;
616 }
617 }
618
619 public boolean hasNext() {
620 return next != null;
621 }
622
623 public E next() {
624 if (next == null) throw new NoSuchElementException();
625 pcurr = pnext;
626 curr = next;
627 pnext = next;
628 next = snext;
629 E x = nextItem;
630 findNext();
631 return x;
632 }
633
634 public void remove() {
635 Node<E> p = curr;
636 if (p == null)
637 throw new IllegalStateException();
638 Object x = p.get();
639 if (x != null && x != p && p.compareAndSet(x, p))
640 clean(pcurr, p);
641 }
642 }
643
644 public E peek() {
645 for (;;) {
646 Node<E> h = traversalHead();
647 Node<E> p = h.next;
648 if (p == null)
649 return null;
650 Object x = p.get();
651 if (p != x) {
652 if (!p.isData)
653 return null;
654 if (x != null)
655 return (E) x;
656 }
657 }
658 }
659
660 public boolean isEmpty() {
661 for (;;) {
662 Node<E> h = traversalHead();
663 Node<E> p = h.next;
664 if (p == null)
665 return true;
666 Object x = p.get();
667 if (p != x) {
668 if (!p.isData)
669 return true;
670 if (x != null)
671 return false;
672 }
673 }
674 }
675
676 public boolean hasWaitingConsumer() {
677 for (;;) {
678 Node<E> h = traversalHead();
679 Node<E> p = h.next;
680 if (p == null)
681 return false;
682 Object x = p.get();
683 if (p != x)
684 return !p.isData;
685 }
686 }
687
688 /**
689 * Returns the number of elements in this queue. If this queue
690 * contains more than {@code Integer.MAX_VALUE} elements, returns
691 * {@code Integer.MAX_VALUE}.
692 *
693 * <p>Beware that, unlike in most collections, this method is
694 * <em>NOT</em> a constant-time operation. Because of the
695 * asynchronous nature of these queues, determining the current
696 * number of elements requires an O(n) traversal.
697 *
698 * @return the number of elements in this queue
699 */
700 public int size() {
701 int count = 0;
702 Node<E> h = traversalHead();
703 for (Node<E> p = h.next; p != null && p.isData; p = p.next) {
704 Object x = p.get();
705 if (x != null && x != p) {
706 if (++count == Integer.MAX_VALUE) // saturated
707 break;
708 }
709 }
710 return count;
711 }
712
713 public int getWaitingConsumerCount() {
714 int count = 0;
715 Node<E> h = traversalHead();
716 for (Node<E> p = h.next; p != null && !p.isData; p = p.next) {
717 if (p.get() == null) {
718 if (++count == Integer.MAX_VALUE)
719 break;
720 }
721 }
722 return count;
723 }
724
725 public int remainingCapacity() {
726 return Integer.MAX_VALUE;
727 }
728
729 public boolean remove(Object o) {
730 if (o == null)
731 return false;
732 for (;;) {
733 Node<E> pred = traversalHead();
734 for (;;) {
735 Node<E> q = pred.next;
736 if (q == null || !q.isData)
737 return false;
738 if (q == pred) // restart
739 break;
740 Object x = q.get();
741 if (x != null && x != q && o.equals(x) &&
742 q.compareAndSet(x, q)) {
743 clean(pred, q);
744 return true;
745 }
746 pred = q;
747 }
748 }
749 }
750
751 /**
752 * Save the state to a stream (that is, serialize it).
753 *
754 * @serialData All of the elements (each an {@code E}) in
755 * the proper order, followed by a null
756 * @param s the stream
757 */
758 private void writeObject(java.io.ObjectOutputStream s)
759 throws java.io.IOException {
760 s.defaultWriteObject();
761 for (E e : this)
762 s.writeObject(e);
763 // Use trailing null as sentinel
764 s.writeObject(null);
765 }
766
767 /**
768 * Reconstitute the Queue instance from a stream (that is,
769 * deserialize it).
770 *
771 * @param s the stream
772 */
773 private void readObject(java.io.ObjectInputStream s)
774 throws java.io.IOException, ClassNotFoundException {
775 s.defaultReadObject();
776 resetHeadAndTail();
777 for (;;) {
778 @SuppressWarnings("unchecked") E item = (E) s.readObject();
779 if (item == null)
780 break;
781 else
782 offer(item);
783 }
784 }
785
786 // Support for resetting head/tail while deserializing
787 private void resetHeadAndTail() {
788 Node<E> dummy = new Node<E>(null, false);
789 UNSAFE.putObjectVolatile(this, headOffset,
790 new PaddedAtomicReference<Node<E>>(dummy));
791 UNSAFE.putObjectVolatile(this, tailOffset,
792 new PaddedAtomicReference<Node<E>>(dummy));
793 UNSAFE.putObjectVolatile(this, cleanMeOffset,
794 new PaddedAtomicReference<Node<E>>(null));
795 }
796
797 // Unsafe mechanics for jsr166y 3rd party package.
798 private static sun.misc.Unsafe getUnsafe() {
799 try {
800 return sun.misc.Unsafe.getUnsafe();
801 } catch (SecurityException se) {
802 try {
803 return java.security.AccessController.doPrivileged
804 (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
805 public sun.misc.Unsafe run() throws Exception {
806 return getUnsafeByReflection();
807 }});
808 } catch (java.security.PrivilegedActionException e) {
809 throw new RuntimeException("Could not initialize intrinsics",
810 e.getCause());
811 }
812 }
813 }
814
815 private static sun.misc.Unsafe getUnsafeByReflection()
816 throws NoSuchFieldException, IllegalAccessException {
817 java.lang.reflect.Field f =
818 sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
819 f.setAccessible(true);
820 return (sun.misc.Unsafe) f.get(null);
821 }
822
823 private static long fieldOffset(String fieldName, Class<?> klazz) {
824 try {
825 return UNSAFE.objectFieldOffset(klazz.getDeclaredField(fieldName));
826 } catch (NoSuchFieldException e) {
827 // Convert Exception to Error
828 NoSuchFieldError error = new NoSuchFieldError(fieldName);
829 error.initCause(e);
830 throw error;
831 }
832 }
833
834 private static final sun.misc.Unsafe UNSAFE = getUnsafe();
835 static final long headOffset =
836 fieldOffset("head", LinkedTransferQueue.class);
837 static final long tailOffset =
838 fieldOffset("tail", LinkedTransferQueue.class);
839 static final long cleanMeOffset =
840 fieldOffset("cleanMe", LinkedTransferQueue.class);
841
842 }