10 |
|
import java.util.concurrent.atomic.*; |
11 |
|
import java.util.*; |
12 |
|
import java.io.*; |
13 |
+ |
import sun.misc.Unsafe; |
14 |
+ |
import java.lang.reflect.*; |
15 |
|
|
16 |
|
/** |
17 |
|
* An unbounded {@linkplain TransferQueue} based on linked nodes. |
133 |
|
} |
134 |
|
|
135 |
|
|
136 |
< |
private final QNode dummy = new QNode(null, false); |
137 |
< |
private final PaddedAtomicReference<QNode> head = |
138 |
< |
new PaddedAtomicReference<QNode>(dummy); |
139 |
< |
private final PaddedAtomicReference<QNode> tail = |
138 |
< |
new PaddedAtomicReference<QNode>(dummy); |
136 |
> |
/** head of the queue */ |
137 |
> |
private transient final PaddedAtomicReference<QNode> head; |
138 |
> |
/** tail of the queue */ |
139 |
> |
private transient final PaddedAtomicReference<QNode> tail; |
140 |
|
|
141 |
|
/** |
142 |
|
* Reference to a cancelled node that might not yet have been |
143 |
|
* unlinked from queue because it was the last inserted node |
144 |
|
* when it cancelled. |
145 |
|
*/ |
146 |
< |
private final PaddedAtomicReference<QNode> cleanMe = |
146 |
< |
new PaddedAtomicReference<QNode>(null); |
146 |
> |
private transient final PaddedAtomicReference<QNode> cleanMe; |
147 |
|
|
148 |
|
/** |
149 |
|
* Tries to cas nh as new head; if successful, unlink |
370 |
|
* Creates an initially empty <tt>LinkedTransferQueue</tt>. |
371 |
|
*/ |
372 |
|
public LinkedTransferQueue() { |
373 |
+ |
QNode dummy = new QNode(null, false); |
374 |
+ |
head = new PaddedAtomicReference<QNode>(dummy); |
375 |
+ |
tail = new PaddedAtomicReference<QNode>(dummy); |
376 |
+ |
cleanMe = new PaddedAtomicReference<QNode>(null); |
377 |
|
} |
378 |
|
|
379 |
|
/** |
385 |
|
* of its elements are null |
386 |
|
*/ |
387 |
|
public LinkedTransferQueue(Collection<? extends E> c) { |
388 |
+ |
this(); |
389 |
|
addAll(c); |
390 |
|
} |
391 |
|
|
683 |
|
private void readObject(java.io.ObjectInputStream s) |
684 |
|
throws java.io.IOException, ClassNotFoundException { |
685 |
|
s.defaultReadObject(); |
686 |
+ |
resetHeadAndTail(); |
687 |
|
for (;;) { |
688 |
|
E item = (E)s.readObject(); |
689 |
|
if (item == null) |
692 |
|
offer(item); |
693 |
|
} |
694 |
|
} |
695 |
+ |
|
696 |
+ |
|
697 |
+ |
// Support for resetting head/tail while deserializing |
698 |
+ |
|
699 |
+ |
// Temporary Unsafe mechanics for preliminary release |
700 |
+ |
private static final Unsafe _unsafe; |
701 |
+ |
private static final long headOffset; |
702 |
+ |
private static final long tailOffset; |
703 |
+ |
private static final long cleanMeOffset; |
704 |
+ |
static { |
705 |
+ |
try { |
706 |
+ |
if (LinkedTransferQueue.class.getClassLoader() != null) { |
707 |
+ |
Field f = Unsafe.class.getDeclaredField("theUnsafe"); |
708 |
+ |
f.setAccessible(true); |
709 |
+ |
_unsafe = (Unsafe)f.get(null); |
710 |
+ |
} |
711 |
+ |
else |
712 |
+ |
_unsafe = Unsafe.getUnsafe(); |
713 |
+ |
headOffset = _unsafe.objectFieldOffset |
714 |
+ |
(LinkedTransferQueue.class.getDeclaredField("head")); |
715 |
+ |
tailOffset = _unsafe.objectFieldOffset |
716 |
+ |
(LinkedTransferQueue.class.getDeclaredField("tail")); |
717 |
+ |
cleanMeOffset = _unsafe.objectFieldOffset |
718 |
+ |
(LinkedTransferQueue.class.getDeclaredField("cleanMe")); |
719 |
+ |
} catch (Exception e) { |
720 |
+ |
throw new RuntimeException("Could not initialize intrinsics", e); |
721 |
+ |
} |
722 |
+ |
} |
723 |
+ |
|
724 |
+ |
private void resetHeadAndTail() { |
725 |
+ |
QNode dummy = new QNode(null, false); |
726 |
+ |
_unsafe.putObjectVolatile(this, headOffset, dummy); |
727 |
+ |
_unsafe.putObjectVolatile(this, tailOffset, dummy); |
728 |
+ |
_unsafe.putObjectVolatile(this, cleanMeOffset, |
729 |
+ |
new PaddedAtomicReference<QNode>(null)); |
730 |
+ |
|
731 |
+ |
} |
732 |
+ |
|
733 |
|
} |