前言
- {@linkplain BlockingQueue阻塞队列},其中每个插入操作必须等待另一个线程进行相应的删除操作,反之亦然。
- 同步队列没有任何内部容量,甚至没有一个容量。
- 您无法在同步队列中{@code peek},因为仅当您尝试删除它时,该元素才存在。
- 您不能插入元素(使用任何方法),除非另一个线程试图将其删除;您无法进行迭代,因为没有要迭代的内容。
- 队列的头部是第一个排队的插入线程试图添加到队列中的元素;如果没有这样的排队线程,则没有元素可用于删除,并且{@code poll()}将返回{@code null}。
- 出于其他{@code Collection}方法(例如{@code contains})的目的,{@code SynchronousQueue}用作空集合。
- 此队列不允许{@code null}元素。
- 同步队列类似于CSP和Ada中使用的集合通道。
- 它们非常适合切换设计,在该设计中,在一个线程中运行的对象必须与在另一个线程中运行的对象同步,以便向其传递一些信息,事件或任务。
- 此类支持可选的公平性策略,用于订购正在等待的生产者和使用者线程。
- 默认情况下,不保证此排序。
- 但是,使用公平性设置为{@code true}构造的队列将按FIFO顺序授予线程访问权限。
- 此类及其迭代器实现{@link Collection}和{@link Iterator}接口的所有可选方法。
- 此类是Java集合框架的成员。
源码
package java.util.concurrent;
public class SynchronousQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
private static final long serialVersionUID = -3223113410248163686L;
/*
* 此类实现W. N. Scherer III和M. L. Scott所著的“不带条件同步的并发对象的无阻塞”中描述的双堆栈和双队列算法的扩展。
第十八届年度大会于2004年10月发布于Distributed Computing(另请参见http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/duals.html)。
(Lifo)堆栈用于非公平模式,(Fifo)队列用于公平模式。
两者的性能通常相似。
Fifo通常在竞争下支持更高的吞吐量,但是Lifo在常见应用程序中保持更高的线程局部性。
双队列(和类似的堆栈)是在任何给定时间保存“数据”(由put操作提供的项,或“请求”)的插槽,表示代入操作,或者为空。
对“实现”的调用(即,从保存数据的队列中请求商品的调用,反之亦然)使互补节点出队。
这些队列最有趣的功能是,任何操作都可以弄清楚队列所处的模式,并且无需锁就可以采取相应的措施。
队列和堆栈都扩展了抽象类Transferer,它们定义了执行放置或取出操作的单个方法。
将它们统一为一个方法,因为在双重数据结构中,放置和取出操作是对称的,因此几乎所有代码都可以合并。
最终的传输方法长远来看,但比分解成几乎重复的部分要容易得多。
队列和堆栈数据结构在概念上有很多相似之处,但具体细节很少。
为简单起见,它们保持不同,以便以后可以分别发展。
这里的算法与上述论文中的版本不同,在于扩展了它们以用于同步队列以及处理取消。
主要区别包括:1.原始算法使用位标记的指针,但此处的算法使用节点中的模式位,从而导致了许多进一步的调整。
2. SynchronousQueues必须阻塞等待实现的线程。
3.支持通过超时和中断进行取消,包括从列表中清除已取消的节点/线程,以避免垃圾保留和内存耗尽。
阻塞主要使用LockSupport暂存区/取消暂存区来完成,除了看起来像是首先要实现的下一个节点外,首先旋转一点(仅在多处理器上)。
在非常繁忙的同步队列上,旋转可以大大提高吞吐量。
在不那么忙碌的纺纱厂上,纺纱的量很小,不足以引起注意。
在队列和堆栈中以不同的方式进行清理。
对于队列,我们几乎总是可以在取消节点后的O(1)时间内立即删除该节点(进行模数重试以进行一致性检查)。
但是,如果可能将其固定为当前尾部,则它必须等到随后进行一些取消。
对于堆栈,我们需要潜在的O(n)遍历,以确保可以删除节点,但这可以与其他访问堆栈的线程同时运行。
尽管垃圾回收会处理大多数会使非阻塞算法复杂化的节点回收问题,但还是要小心“忘记”对数据,其他节点和可能被阻塞线程长期保留的线程的引用。
如果设置为null会与主要算法冲突,则可以通过将节点的链接更改为现在指向节点本身来完成。
对于Stack节点,这不会发生太多(因为阻塞的线程不会挂在旧的头部指针上),但是必须积极地忘记Queue节点中的引用,以避免自到达以来任何节点曾经引用的所有内容都可以访问。
*/
/**
* Shared internal API for dual stacks and queues.
*/
abstract static class Transferer<E> {
/**
* Performs a put or take.
* 执行一个put或者一个take
* @param e if non-null, the item to be handed to a consumer;
* if null, requests that transfer return an item
* offered by producer.
* @param timed if this operation should timeout
* @param nanos the timeout, in nanoseconds
* @return if non-null, the item provided or received; if null,
* the operation failed due to timeout or interrupt --
* the caller can distinguish which of these occurred
* by checking Thread.interrupted.
*/
abstract E transfer(E e, boolean timed, long nanos);
}
/** The number of CPUs, for spin control */
static final int NCPUS = Runtime.getRuntime().availableProcessors();
/**
* 在阻塞等待时间之前旋转的次数。
* 该值是根据经验得出的-在各种处理器和OS上都可以很好地工作。
* 根据经验,最佳值似乎不会随CPU数量(超过2个)而变化,因此只是一个常数。
*
*/
static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
/**
* 在阻塞未定时的等待之前旋转的次数。
* 此值大于定时值,因为非定时等待旋转得更快,因为它们不需要每次旋转都检查时间。
*
*/
static final int maxUntimedSpins = maxTimedSpins * 16;
/**
* 旋转秒级比使用定时停泊更快的纳秒数。
* 粗略的估计就足够了。
*
*/
static final long spinForTimeoutThreshold = 1000L;
/** Dual stack */
static final class Transf
static final int REQUEST = 0;
static final int DATA = 1;
static final int FULFILLING = 2;
static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; }
static final class SNode {
volatile SNode next;
volatile SNode match;
volatile Thread waiter;
Object item;
int mode;
SNode(Object item) {
this.item = item;
}
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
/**
* 尝试将节点s与此节点匹配,如果是,则唤醒线程。
* Fulfiller呼叫tryMatch来识别其服务员。
* 服务员封锁直到他们被匹配。
*
*/
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;
}
/**
* Tries to cancel a wait by matching node to itself.
*/
void tryCancel() {
UNSAFE.compareAndSwapObject(this, matchOffset, null, this);
}
boolean isCancelled() {
return match == this;
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long matchOffset;
private static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = SNode.class;
matchOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("match"));
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
/** The head (top) of the stack */
volatile SNode head;
boolean casHead(SNode h, SNode nh) {
return h == head &&
UNSAFE.compareAndSwapObject(this, headOffset, h, nh);
}
/**
* 创建或重置节点的字段。
* 仅从传输中调用,在该调用中延迟创建要推送到栈上的节点,并在可能的情况下重用该副本,以帮助减少读取和头的CASes之间的间隔,并避免当CASes推送节点因争用而失败时产生的大量垃圾。
*
*/
static SNode snode(SNode s, Object e, SNode next, int mode) {
if (s == null) s = new SNode(e);
s.mode = mode;
s.next = next;
return s;
}
/**
* Puts or takes an item.
*/
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {
/*
* 基本算法是循环尝试以下三种操作之一:
1.如果明显为空或已经包含相同模式的节点,请尝试将节点压入堆栈并等待匹配,然后将其返回,如果取消则返回null。
2.如果显然包含互补模式的节点,请尝试将满足条件的节点推入堆栈,与相应的等待节点匹配,从堆栈中弹出两者,然后返回匹配项。
由于其他线程正在执行操作3,因此实际上可能不需要匹配或取消链接:
3.如果栈顶已经包含另一个实现节点,请通过执行其match和/或pop操作来帮助它,然后继续。
帮助代码与实现代码基本相同,除了它不返回项目外。
*/
SNode s = null; // constructed/reused as needed
int mode = (e == null) ? REQUEST : DATA;
for (;;) {
SNode h = head;
if (h == null || h.mode == mode) { // empty or same-mode
if (timed && nanos <= 0) { // can't wait
if (h != null && h.isCancelled())
casHead(h, h.next); // pop cancelled node
else
return null;
} else if (casHead(h, s = snode(s, e, h, mode))) {
SNode m = awaitFulfill(s, timed, nanos);
if (m == s) { // wait was cancelled
clean(s);
return null;
}
if ((h = head) != null && h.next == s)
casHead(h, s.next); // help s's fulfiller
return (E) ((mode == REQUEST) ? m.item : s.item);
}
} else if (!isFulfilling(h.mode)) { // try to fulfill
if (h.isCancelled()) // already cancelled
casHead(h, h.next); // pop and retry
else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
for (;;) { // loop until matched or waiters disappear
SNode m = s.next; // m is s's match
if (m == null) { // all waiters are gone
casHead(s, null); // pop fulfill node
s = null; // use new node next time
break; // restart main loop
}
SNode mn = m.next;
if (m.tryMatch(s)) {
casHead(s, mn); // pop both s and m
return (E) ((mode == REQUEST) ? m.item : s.item);
} else // lost match
s.casNext(m, mn); // help unlink
}
}
} else { // help a fulfiller
SNode m = h.next; // m is h's match
if (m == null) // waiter is gone
casHead(h, null); // pop fulfilling node
else {
SNode mn = m.next;
if (m.tryMatch(h)) // help match
casHead(h, mn); // pop both h and m
else // lost match
h.casNext(m, mn); // help unlink
}
}
}
}
SNode awaitFulfill(SNode s, boolean timed, long nanos) {
/*
* 当节点/线程将要阻塞时,它会设置其服务员字段,然后在实际停车之前至少再检查一次状态,从而涵盖了竞争与实现者的关系,并注意到服务员为非空,因此应将其唤醒。
当由出现在调用点位于堆栈顶部的节点调用时,对停放的调用之前会进行旋转,以避免在生产者和消费者及时到达时阻塞。
这可能足以只在多处理器上发生。
从主循环返回的检查顺序反映了这样一个事实,即中断的优先级高于正常的返回,而正常的返回优先于超时。
(因此,在超时时,在放弃之前要进行最后一次匹配检查。
)除了来自非定时SynchronousQueue的调用。
{poll /offer}不会检查中断,根本不等待,因此陷入了转移方法中而不是调用awaitFulfill。
*/
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
int spins = (shouldSpin(s) ?
(timed ? maxTimedSpins : maxUntimedSpins) : 0);
for (;;) {
if (w.isInterrupted())
s.tryCancel();
SNode m = s.match;
if (m != null)
return m;
if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
s.tryCancel();
continue;
}
}
if (spins > 0)
spins = shouldSpin(s) ? (spins-1) : 0;
else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter
else if (!timed)
LockSupport.park(this);
else if (nanos > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanos);
}
}
/**
* Returns true if node s is at head or there is an active
* fulfiller.
*/
boolean shouldSpin(SNode s) {
SNode h = head;
return (h == s || h == null || isFulfilling(h.mode));
}
/**
* Unlinks s from the stack.
*/
void clean(SNode s) {
s.item = null; // forget item
s.waiter = null; // forget thread
/*
最糟糕的是,我们可能需要遍历整个堆栈以取消s的链接。
如果有多个并发调用要清理,则如果另一个线程已将其删除,则可能看不到。
但是当看到任何已知跟随s的节点时,我们可以停止。
除非也将其取消,否则我们将使用s.next,在这种情况下,我们将尝试过去一个节点。
我们不做进一步检查,因为我们不想为了找到标记而进行双重遍历。
*/
SNode past = s.next;
if (past != null && past.isCancelled())
past = past.next;
// Absorb cancelled nodes at head
SNode p;
while ((p = head) != null && p != past && p.isCancelled())
casHead(p, p.next);
// Unsplice embedded nodes
while (p != null && p != past) {
SNode n = p.next;
if (n != null && n.isCancelled())
p.casNext(n, n.next);
else
p = n;
}
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long headOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = TransferStack.class;
headOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("head"));
} catch (Exception e) {
throw new Error(e);
}
}
}
/** Dual Queue */
static final class TransferQueue<E> extends Transferer<E> {
/*
* 这扩展了Scherer-Scott双队列算法,其不同之处在于,它使用节点内的模式而不是标记的指针。
该算法比用于堆栈的算法简单一些,因为实现者不需要显式节点,并且匹配是通过CAS的QNode.item字段从非null到null(用于放置)或反之亦然(用于获取)来完成的。
*/
/** Node class for TransferQueue. */
static final class QNode {
volatile QNode next; // next node in queue
volatile Object item; // CAS'ed to or from null
volatile Thread waiter; // to control park/unpark
final boolean isData;
QNode(Object item, boolean isData) {
this.item = item;
this.isData = isData;
}
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
boolean casItem(Object cmp, Object val) {
return item == cmp &&
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
/**
* Tries to cancel by CAS'ing ref to this as item.
*/
void tryCancel(Object cmp) {
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
}
boolean isCancelled() {
return item == this;
}
/**
* Returns true if this node is known to be off the queue
* because its next pointer has been forgotten due to
* an advanceHead operation.
*/
boolean isOffList() {
return next == this;
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long itemOffset;
private static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = QNode.class;
itemOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("item"));
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
/** Head of queue */
transient volatile QNode head;
/** Tail of queue */
transient volatile QNode tail;
/**
* Reference to a cancelled node that might not yet have been
* unlinked from queue because it was the last inserted node
* when it was cancelled.
*/
transient volatile QNode cleanMe;
TransferQueue() {
QNode h = new QNode(null, false); // initialize to dummy node.
head = h;
tail = h;
}
/**
* 尝试以cas nh作为新负责人;如果成功,则取消旧头的下一个节点的链接以避免垃圾保留。
*/
void advanceHead(QNode h, QNode nh) {
if (h == head &&
UNSAFE.compareAndSwapObject(this, headOffset, h, nh))
h.next = h; // forget old next
}
/**
* Tries to cas nt as new tail.
*/
void advanceTail(QNode t, QNode nt) {
if (tail == t)
UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);
}
/**
* Tries to CAS cleanMe slot.
*/
boolean casCleanMe(QNode cmp, QNode val) {
return cleanMe == cmp &&
UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val);
}
/**
* Puts or takes an item.
*/
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {
/*
* 基本算法是循环尝试执行以下两个操作之一:
1.如果队列明显为空或持有相同模式的节点,请尝试将节点添加到服务员队列中,等待被实现(或取消)并返回匹配项。
2.如果队列显然包含等待项,并且此调用是互补模式,请尝试通过对等待节点的CAS'ing item字段进行排队并将其出队,然后返回匹配项来实现。
在每种情况下,一路检查并尝试帮助其他停滞/缓慢的线程推进头和尾。
循环以空检查开始,以防止看到未初始化的头或尾值。
这在当前的SynchronousQueue中永远不会发生,但是如果调用者持有对传输者的非易失性/最终引用,则可能会发生这种情况。
无论如何,这里的检查是因为将空检查放在循环的顶部,通常比隐式散布检查要快。
*/
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) ? (E)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) ? (E)x : e;
}
}
}
/**
* Spins/blocks until node s is fulfilled.
* Spins/blocks,直到满足节点s为止。
* @param s the waiting node
* @param e the comparison value for checking match
* @param timed true if timed wait
* @param nanos timeout value
* @return matched item, or s if cancelled
*/
Object awaitFulfill(QNode s, E e, boolean timed, long nanos) {
/* Same idea as TransferStack.awaitFulfill */
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
int spins = ((head.next == s) ?
(timed ? maxTimedSpins : maxUntimedSpins) : 0);
for (;;) {
if (w.isInterrupted())
s.tryCancel(e);
Object x = s.item;
if (x != e)
return x;
if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
s.tryCancel(e);
continue;
}
}
if (spins > 0)
--spins;
else if (s.waiter == null)
s.waiter = w;
else if (!timed)
LockSupport.park(this);
else if (nanos > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanos);
}
}
/**
* Gets rid of cancelled node s with original predecessor pred.
* 删除具有原始前任pred的已取消节点s。
*/
void clean(QNode pred, QNode s) {
s.waiter = null; // forget thread
/*
* 在任何给定时间,列表中的一个节点都不能删除-最后插入的节点。为了解决这个问题,如果我们不能删除s,我们将其前身保存为“ cleanMe”,首先删除之前保存的版本。节点s或先前保存的节点中的至少一个始终可以被删除,因此它总是终止。
*/
while (pred.next == s) { // Return early if already unlinked
QNode h = head;
QNode hn = h.next; // Absorb cancelled first node as head
if (hn != null && hn.isCancelled()) {
advanceHead(h, hn);
continue;
}
QNode t = tail; // Ensure consistent read for tail
if (t == h)
return;
QNode tn = t.next;
if (t != tail)
continue;
if (tn != null) {
advanceTail(t, tn);
continue;
}
if (s != t) { // If not tail, try to unsplice
QNode sn = s.next;
if (sn == s || pred.casNext(s, sn))
return;
}
QNode dp = cleanMe;
if (dp != null) { // Try unlinking previous cancelled node
QNode d = dp.next;
QNode dn;
if (d == null || // d is gone or
d == dp || // d is off list or
!d.isCancelled() || // d not cancelled or
(d != t && // d not tail and
(dn = d.next) != null && // has successor
dn != d && // that is on list
dp.casNext(d, dn))) // d unspliced
casCleanMe(dp, null);
if (dp == pred)
return; // s is already saved node
} else if (casCleanMe(null, pred))
return; // Postpone cleaning s
}
}
private static final sun.misc.Unsafe UNSAFE;
private static final long headOffset;
private static final long tailOffset;
private static final long cleanMeOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = TransferQueue.class;
headOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("head"));
tailOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("tail"));
cleanMeOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("cleanMe"));
} catch (Exception e) {
throw new Error(e);
}
}
}
/**
* transferer。
* 仅在构造函数中设置,但在不使序列化进一步复杂的情况下不能将其声明为final。
* 由于每个公用方法最多只能访问一次,因此在这里使用volatile而不是final不会显着降低性能。
*
*/
private transient volatile Transferer<E> transferer;
/**
* Creates a {@code SynchronousQueue} with nonfair access policy.
*/
public SynchronousQueue() {
this(false);
}
/**
* Creates a {@code SynchronousQueue} with the specified fairness policy.
*
* @param fair if true, waiting threads contend in FIFO order for
* access; otherwise the order is unspecified.
*/
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
/**
* 将指定的元素添加到此队列,如果有必要,等待另一个线程接收它。
*/
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, false, 0) == null) {
Thread.interrupted();
throw new InterruptedException();
}
}
/**
* 将指定的元素插入此队列,如有必要,请等待指定的等待时间,以便另一个线程接收它。
*/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
return true;
if (!Thread.interrupted())
return false;
throw new InterruptedException();
}
/**
* 如果另一个线程正在等待接收指定的元素,则将其插入此队列。
*/
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
return transferer.transfer(e, true, 0) != null;
}
/**
* 检索并删除此队列的头部,如有必要,等待其他线程将其插入。
*/
public E take() throws InterruptedException {
E e = transferer.transfer(null, false, 0);
if (e != null)
return e;
Thread.interrupted();
throw new InterruptedException();
}
/**
* 检索并删除此队列的头,如有必要,可等待指定的等待时间,直到另一个线程将其插入。
*/
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E e = transferer.transfer(null, true, unit.toNanos(timeout));
if (e != null || !Thread.interrupted())
return e;
throw new InterruptedException();
}
/**
* 如果另一个线程当前正在使元素可用,则检索并删除此队列的头部。
}
/**
* Always returns {@code true}.
* A {@code SynchronousQueue} has no internal capacity.
*
* @return {@code true}
*/
public boolean isEmpty() {
return true;
}
/**
* Always returns zero.
* A {@code SynchronousQueue} has no internal capacity.
*
* @return zero
*/
public int size() {
return 0;
}
/**
* Always returns zero.
* A {@code SynchronousQueue} has no internal capacity.
*
* @return zero
*/
public int remainingCapacity() {
return 0;
}
/**
* Does nothing.
* A {@code SynchronousQueue} has no internal capacity.
*/
public void clear() {
}
/**
* Always returns {@code false}.
* A {@code SynchronousQueue} has no internal capacity.
*
* @param o the element
* @return {@code false}
*/
public boolean contains(Object o) {
return false;
}
/**
* Always returns {@code false}.
* A {@code SynchronousQueue} has no internal capacity.
*
* @param o the element to remove
* @return {@code false}
*/
public boolean remove(Object o) {
return false;
}
/**
* Returns {@code false} unless the given collection is empty.
* A {@code SynchronousQueue} has no internal capacity.
*
* @param c the collection
* @return {@code false} unless given collection is empty
*/
public boolean containsAll(Collection<?> c) {
return c.isEmpty();
}
/**
* Always returns {@code false}.
* A {@code SynchronousQueue} has no internal capacity.
*
* @param c the collection
* @return {@code false}
*/
public boolean removeAll(Collection<?> c) {
return false;
}
/**
* Always returns {@code false}.
* A {@code SynchronousQueue} has no internal capacity.
*
* @param c the collection
* @return {@code false}
*/
public boolean retainAll(Collection<?> c) {
return false;
}
/**
* Always returns {@code null}.
* A {@code SynchronousQueue} does not return elements
* unless actively waited on.
*
* @return {@code null}
*/
public E peek() {
return null;
}
/**
* Returns an empty iterator in which {@code hasNext} always returns
* {@code false}.
*
* @return an empty iterator
*/
public Iterator<E> iterator() {
return Collections.emptyIterator();
}
/**
* Returns an empty spliterator in which calls to
* {@link java.util.Spliterator
*
* @return an empty spliterator
* @since 1.8
*/
public Spliterator<E> spliterator() {
return Spliterators.emptySpliterator();
}
/**
* Returns a zero-length array.
* @return a zero-length array
*/
public Object[] toArray() {
return new Object[0];
}
/**
* Sets the zeroeth element of the specified array to {@code null}
* (if the array has non-zero length) and returns it.
*
* @param a the array
* @return the specified array
* @throws NullPointerException if the specified array is null
*/
public <T> T[] toArray(T[] a) {
if (a.length > 0)
a[0] = null;
return a;
}
/**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
int n = 0;
for (E e; (e = poll()) != null;) {
c.add(e);
++n;
}
return n;
}
/**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
int n = 0;
for (E e; n < maxElements && (e = poll()) != null;) {
c.add(e);
++n;
}
return n;
}
/*
* To cope with serialization strategy in the 1.5 version of
* SynchronousQueue, we declare some unused classes and fields
* that exist solely to enable serializability across versions.
* These fields are never used, so are initialized only if this
* object is ever serialized or deserialized.
*/
@SuppressWarnings("serial")
static class WaitQueue implements java.io.Serializable { }
static class LifoWaitQueue extends WaitQueue {
private static final long serialVersionUID = -3633113410248163686L;
}
static class FifoWaitQueue extends WaitQueue {
private static final long serialVersionUID = -3623113410248163686L;
}
private ReentrantLock qlock;
private WaitQueue waitingProducers;
private WaitQueue waitingConsumers;
/**
* Saves this queue to a stream (that is, serializes it).
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
boolean fair = transferer instanceof TransferQueue;
if (fair) {
qlock = new ReentrantLock(true);
waitingProducers = new FifoWaitQueue();
waitingConsumers = new FifoWaitQueue();
}
else {
qlock = new ReentrantLock();
waitingProducers = new LifoWaitQueue();
waitingConsumers = new LifoWaitQueue();
}
s.defaultWriteObject();
}
/**
* 从流中重构此队列(即反序列化)。
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
if (waitingProducers instanceof FifoWaitQueue)
transferer = new TransferQueue<E>();
else
transferer = new TransferStack<E>();
}
// Unsafe mechanics
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// Convert Exception to corresponding Error
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
}