我正在浏览ArrayBlockingQueue和LinkedBlockingQueue的源代码。 LinkedBlockingQueue有一个putLock和一个takeLock分别用于插入和删除,但ArrayBlockingQueue只使用1个锁。我相信LinkedBlockingQueue是基于Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms中描述的设计实现的。在本文中,他们提到他们保留一个虚拟节点,以便入队者永远不必访问头部,并且出队员永远不必访问尾部,这避免了死锁情况。我想知道为什么ArrayBlockingQueue没有借用相同的想法而是使用2个锁。
答案 0 :(得分:9)
ArrayBlockingQueue必须避免覆盖条目,以便它需要知道开始和结束的位置。 LinkedBlockQueue不需要知道这一点,因为它让GC担心清理队列中的节点。
答案 1 :(得分:9)
我想知道为什么ArrayBlockingQueue没有借用相同的想法而是使用2个锁。
因为ArrayBlockingQueue
使用更简单的数据结构来保存队列项。
ArrayBlockingQueue
将其数据存储在一个private final E[] items;
数组中。对于处理相同存储空间的多个线程,无论是添加还是出列,它们都必须使用相同的锁。这不仅是因为内存屏障,而且因为它们正在修改相同的数组,因此会受到互斥保护。
LinkedBlockingQueue
是队列元素的链接列表,它完全不同,并且允许具有双锁的能力。它是队列中元素的内部存储,启用了不同的锁配置。
答案 2 :(得分:1)
在LBQ中使用2个锁来限制对头部的访问和同时锁定。头锁不允许同时删除两个元素,尾部锁定不允许两个元素同时添加到队列中。两个锁在一起防止比赛。
答案 3 :(得分: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。