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; |
17 |
|
|
18 |
|
/** |
19 |
|
* An unbounded {@linkplain TransferQueue} based on linked nodes. |
114 |
|
this.isData = isData; |
115 |
|
} |
116 |
|
|
117 |
< |
@SuppressWarnings("rawtypes") |
118 |
< |
static final AtomicReferenceFieldUpdater<Node, Node> |
119 |
< |
nextUpdater = AtomicReferenceFieldUpdater.newUpdater |
120 |
< |
(Node.class, Node.class, "next"); |
117 |
> |
// Unsafe mechanics |
118 |
> |
|
119 |
> |
private static final sun.misc.Unsafe UNSAFE = getUnsafe(); |
120 |
> |
private static final long nextOffset = |
121 |
> |
objectFieldOffset(UNSAFE, "next", Node.class); |
122 |
|
|
123 |
|
final boolean casNext(Node<E> cmp, Node<E> val) { |
124 |
< |
return nextUpdater.compareAndSet(this, cmp, val); |
124 |
> |
return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); |
125 |
|
} |
126 |
|
|
127 |
|
final void clearNext() { |
128 |
< |
nextUpdater.lazySet(this, this); |
128 |
> |
UNSAFE.putOrderedObject(this, nextOffset, this); |
129 |
> |
} |
130 |
> |
|
131 |
> |
/** |
132 |
> |
* Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. |
133 |
> |
* Replace with a simple call to Unsafe.getUnsafe when integrating |
134 |
> |
* into a jdk. |
135 |
> |
* |
136 |
> |
* @return a sun.misc.Unsafe |
137 |
> |
*/ |
138 |
> |
private static sun.misc.Unsafe getUnsafe() { |
139 |
> |
try { |
140 |
> |
return sun.misc.Unsafe.getUnsafe(); |
141 |
> |
} catch (SecurityException se) { |
142 |
> |
try { |
143 |
> |
return java.security.AccessController.doPrivileged |
144 |
> |
(new java.security |
145 |
> |
.PrivilegedExceptionAction<sun.misc.Unsafe>() { |
146 |
> |
public sun.misc.Unsafe run() throws Exception { |
147 |
> |
java.lang.reflect.Field f = sun.misc |
148 |
> |
.Unsafe.class.getDeclaredField("theUnsafe"); |
149 |
> |
f.setAccessible(true); |
150 |
> |
return (sun.misc.Unsafe) f.get(null); |
151 |
> |
}}); |
152 |
> |
} catch (java.security.PrivilegedActionException e) { |
153 |
> |
throw new RuntimeException("Could not initialize intrinsics", |
154 |
> |
e.getCause()); |
155 |
> |
} |
156 |
> |
} |
157 |
|
} |
158 |
|
|
159 |
|
private static final long serialVersionUID = -3375979862319811754L; |
635 |
|
} |
636 |
|
} |
637 |
|
|
610 |
– |
|
638 |
|
public Iterator<E> iterator() { |
639 |
|
return new Itr(); |
640 |
|
} |
649 |
|
class Itr implements Iterator<E> { |
650 |
|
Node<E> next; // node to return next |
651 |
|
Node<E> pnext; // predecessor of next |
625 |
– |
Node<E> snext; // successor of next |
652 |
|
Node<E> curr; // last returned node, for remove() |
653 |
|
Node<E> pcurr; // predecessor of curr, for remove() |
654 |
< |
E nextItem; // Cache of next item, once committed to in next |
654 |
> |
E nextItem; // Cache of next item, once committed to in next |
655 |
|
|
656 |
|
Itr() { |
657 |
< |
findNext(); |
657 |
> |
advance(); |
658 |
|
} |
659 |
|
|
660 |
|
/** |
661 |
< |
* Ensures next points to next valid node, or null if none. |
661 |
> |
* Moves to next valid node and returns item to return for |
662 |
> |
* next(), or null if no such. |
663 |
|
*/ |
664 |
< |
void findNext() { |
664 |
> |
private E advance() { |
665 |
> |
pcurr = pnext; |
666 |
> |
curr = next; |
667 |
> |
E item = nextItem; |
668 |
> |
|
669 |
|
for (;;) { |
670 |
< |
Node<E> pred = pnext; |
671 |
< |
Node<E> q = next; |
672 |
< |
if (pred == null || pred == q) { |
642 |
< |
pred = traversalHead(); |
643 |
< |
q = pred.next; |
644 |
< |
} |
645 |
< |
if (q == null || !q.isData) { |
670 |
> |
pnext = next == null ? traversalHead() : next; |
671 |
> |
next = pnext.next; |
672 |
> |
if (next == pnext) { |
673 |
|
next = null; |
674 |
< |
return; |
674 |
> |
continue; // restart |
675 |
|
} |
676 |
< |
Object x = q.get(); |
677 |
< |
Node<E> s = q.next; |
678 |
< |
if (x != null && q != x && q != s) { |
676 |
> |
if (next == null) |
677 |
> |
break; |
678 |
> |
Object x = next.get(); |
679 |
> |
if (x != null && x != next) { |
680 |
|
nextItem = (E) x; |
681 |
< |
snext = s; |
654 |
< |
pnext = pred; |
655 |
< |
next = q; |
656 |
< |
return; |
681 |
> |
break; |
682 |
|
} |
658 |
– |
pnext = q; |
659 |
– |
next = s; |
683 |
|
} |
684 |
+ |
return item; |
685 |
|
} |
686 |
|
|
687 |
|
public boolean hasNext() { |
689 |
|
} |
690 |
|
|
691 |
|
public E next() { |
692 |
< |
if (next == null) throw new NoSuchElementException(); |
693 |
< |
pcurr = pnext; |
694 |
< |
curr = next; |
671 |
< |
pnext = next; |
672 |
< |
next = snext; |
673 |
< |
E x = nextItem; |
674 |
< |
findNext(); |
675 |
< |
return x; |
692 |
> |
if (next == null) |
693 |
> |
throw new NoSuchElementException(); |
694 |
> |
return advance(); |
695 |
|
} |
696 |
|
|
697 |
|
public void remove() { |
761 |
|
* @return the number of elements in this queue |
762 |
|
*/ |
763 |
|
public int size() { |
764 |
< |
int count = 0; |
765 |
< |
Node<E> h = traversalHead(); |
766 |
< |
for (Node<E> p = h.next; p != null && p.isData; p = p.next) { |
767 |
< |
Object x = p.get(); |
768 |
< |
if (x != null && x != p) { |
769 |
< |
if (++count == Integer.MAX_VALUE) // saturated |
764 |
> |
for (;;) { |
765 |
> |
int count = 0; |
766 |
> |
Node<E> pred = traversalHead(); |
767 |
> |
for (;;) { |
768 |
> |
Node<E> q = pred.next; |
769 |
> |
if (q == pred) // restart |
770 |
|
break; |
771 |
+ |
if (q == null || !q.isData) |
772 |
+ |
return count; |
773 |
+ |
Object x = q.get(); |
774 |
+ |
if (x != null && x != q) { |
775 |
+ |
if (++count == Integer.MAX_VALUE) // saturated |
776 |
+ |
return count; |
777 |
+ |
} |
778 |
+ |
pred = q; |
779 |
|
} |
780 |
|
} |
754 |
– |
return count; |
781 |
|
} |
782 |
|
|
783 |
|
public int getWaitingConsumerCount() { |
784 |
< |
int count = 0; |
785 |
< |
Node<E> h = traversalHead(); |
786 |
< |
for (Node<E> p = h.next; p != null && !p.isData; p = p.next) { |
787 |
< |
if (p.get() == null) { |
788 |
< |
if (++count == Integer.MAX_VALUE) |
784 |
> |
// converse of size -- count valid non-data nodes |
785 |
> |
for (;;) { |
786 |
> |
int count = 0; |
787 |
> |
Node<E> pred = traversalHead(); |
788 |
> |
for (;;) { |
789 |
> |
Node<E> q = pred.next; |
790 |
> |
if (q == pred) // restart |
791 |
|
break; |
792 |
+ |
if (q == null || q.isData) |
793 |
+ |
return count; |
794 |
+ |
Object x = q.get(); |
795 |
+ |
if (x == null) { |
796 |
+ |
if (++count == Integer.MAX_VALUE) // saturated |
797 |
+ |
return count; |
798 |
+ |
} |
799 |
+ |
pred = q; |
800 |
|
} |
801 |
|
} |
766 |
– |
return count; |
767 |
– |
} |
768 |
– |
|
769 |
– |
public int remainingCapacity() { |
770 |
– |
return Integer.MAX_VALUE; |
802 |
|
} |
803 |
|
|
804 |
|
public boolean remove(Object o) { |
808 |
|
Node<E> pred = traversalHead(); |
809 |
|
for (;;) { |
810 |
|
Node<E> q = pred.next; |
780 |
– |
if (q == null || !q.isData) |
781 |
– |
return false; |
811 |
|
if (q == pred) // restart |
812 |
|
break; |
813 |
+ |
if (q == null || !q.isData) |
814 |
+ |
return false; |
815 |
|
Object x = q.get(); |
816 |
|
if (x != null && x != q && o.equals(x) && |
817 |
|
q.compareAndSet(x, q)) { |
823 |
|
} |
824 |
|
} |
825 |
|
|
826 |
+ |
public int remainingCapacity() { |
827 |
+ |
return Integer.MAX_VALUE; |
828 |
+ |
} |
829 |
+ |
|
830 |
|
/** |
831 |
|
* Save the state to a stream (that is, serialize it). |
832 |
|
* |
877 |
|
|
878 |
|
private static final sun.misc.Unsafe UNSAFE = getUnsafe(); |
879 |
|
private static final long headOffset = |
880 |
< |
objectFieldOffset("head", LinkedTransferQueue.class); |
880 |
> |
objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class); |
881 |
|
private static final long tailOffset = |
882 |
< |
objectFieldOffset("tail", LinkedTransferQueue.class); |
882 |
> |
objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class); |
883 |
|
private static final long cleanMeOffset = |
884 |
< |
objectFieldOffset("cleanMe", LinkedTransferQueue.class); |
884 |
> |
objectFieldOffset(UNSAFE, "cleanMe", LinkedTransferQueue.class); |
885 |
> |
|
886 |
|
|
887 |
< |
private static long objectFieldOffset(String field, Class<?> klazz) { |
887 |
> |
static long objectFieldOffset(sun.misc.Unsafe UNSAFE, |
888 |
> |
String field, Class<?> klazz) { |
889 |
|
try { |
890 |
|
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); |
891 |
|
} catch (NoSuchFieldException e) { |