ArrayBlockingQueue使用单个锁进行插入和删除,但LinkedBlockingQueue使用2个单独的锁

我正在浏览ArrayBlockingQueue和LinkedBlockingQueue的源代码。 LinkedBlockingQueue有一个putLock和一个takeLock分别用于插入和删除,但ArrayBlockingQueue只使用1个锁。 我相信LinkedBlockingQueue是基于简单,快速,实用的非阻塞和阻塞并发队列算法中描述的设计实现的 。 在本文中,他们提到他们保留一个虚拟节点,以便入队者永远不必访问头部,而且出队员永远不必访问尾部,这避免了死锁情况。 我想知道为什么ArrayBlockingQueue没有借用相同的想法并使用2个锁而不是。

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

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

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

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

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

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

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

他们没有使用它的原因主要是因为实现的复杂性,特别是迭代器和复杂性与性能增益之间的权衡并不是那么有利可图。

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