LinkedBlocking Queue 有两个锁,一个用于放入,一个用于取出。当队列的大小为1时,我认为两个线程可以同时锁定和操作队列,这将导致未定义的行为。我错了吗?
// method put: // method take:
// put lock // take lock
putLocK.lockInterruptibly(); takeLock.lockInterruptibly();
... ...
while(count.get() == capacity){ while(count.get() == 0){
notFull.await(); notEmpty.await();
} }
enqueue(node); x = dequeue();
// method enqueue: // method dequeue:
last = last.next = node; Node<E> h = head;
... Node<E> first = h.next;
h.next = h;
head = first;
E x = first.item;
first.item = null;
return x;
显然,当队列中只有一项时,put 线程和 take 线程会锁定,因此它们将分别执行 enqueue 和 dequeue 方法中的代码。我的意思是,如果 take 线程进入方法出队,在所有指针修改之后,不会与入队中的代码发生冲突吗?
这里的链接说“然而,当队列为空时,争用就无法避免,因此需要额外的代码来处理这种常见的‘边缘’情况”
最佳答案
javadoc对于 BlockingQueue(LinkedBlockingQueue 的父类(super class))来说:
BlockingQueue
implementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or other forms of concurrency control.
“原子”一词意味着如果两个操作(例如 put
和 take
)同时发生,那么实现将确保它们的行为符合契约(Contract)。效果将如同,put
发生在get
之前,反之亦然。这也适用于边缘情况,例如包含一个元素的队列示例。
事实上,由于 put
和 get
是阻塞操作,因此这两个操作的相对顺序并不重要。使用 offer
/poll
或 add
/remove
顺序确实很重要,但是你无法控制。
请注意,上述内容仅基于 javadoc 的内容。假设我正确解释了 javadoc,那么它适用于所有1 BlockingQueue
实现,无论它们是否使用一个或两个锁......或者根本不使用。如果 BlockingQueue
实现的行为与上述不同,那就是一个错误!
1 - 正确实现 API 的所有实现。这应该涵盖所有 Java SE 类。
关于java - 当Java LinkedBlocking Queue只有一个元素时,如果同时放入和取出会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56114156/