10

我正在浏览 ArrayBlockingQueue 和 LinkedBlockingQueue 的源代码。LinkedBlockingQueue 有一个 putLock 和一个 takeLock 分别用于插入和删除,但 ArrayBlockingQueue 只使用 1 个锁。我相信 LinkedBlockingQueue 是基于Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms中描述的设计实现的。在本文中,他们提到他们保留了一个虚拟节点,以便入队者永远不必访问头,而出队者永远不必访问尾,从而避免了死锁情况。我想知道为什么 ArrayBlockingQueue 不借用相同的想法而是使用 2 个锁。

4

4 回答 4

11

ArrayBlockingQueue 必须避免覆盖条目,以便它需要知道开始和结束的位置。LinkedBlockQueue 不需要知道这一点,因为它让 GC 担心清理队列中的节点。

于 2012-06-13T13:16:16.787 回答
10

我想知道为什么 ArrayBlockingQueue 不借用相同的想法而是使用 2 个锁。

因为它ArrayBlockingQueue使用更简单的数据结构来保存队列项。

ArrayBlockingQueue其数据存储在一个private final E[] items;数组中。对于多个线程来处理相同的存储空间,无论是添加还是出列,它们都必须使用相同的锁。这不仅是因为内存屏障,还因为互斥保护,因为它们正在修改同一个数组。

LinkedBlockingQueue另一方面是完全不同的队列元素的链表,它允许具有双锁的能力。启用不同锁配置的是队列中元素的内部存储。

于 2012-06-13T13:16:25.447 回答
1

LBQ 中使用了 2 个锁来限制对 head 和 lock 的并发访问。头锁不允许同时删除两个元素,尾锁不允许同时将两个元素添加到队列中。两者锁定在一起防止比赛。

于 2017-06-10T18:37:28.883 回答
0

我认为 ABQ 有可能借用与 LBQ 相同的想法。请参考我的代码http://pastebin.com/ZD1uFy7S和我在 SO ArrayBlockingQueue: concurrent put and take上提出的类似问题。

他们之所以没有使用它,主要是因为实现的复杂性,尤其是迭代器,并且在复杂性和性能增益之间的权衡并不是那么有利可图。

如需更多参考,请查看http://jsr166-concurrency.10961.n7.nabble.com/ArrayBlockingQueue-concurrent-put-and-take-tc1306.html

于 2014-07-07T17:05:14.677 回答