为什么未使用LinkedBlockingQueue方法实现ABQ。我们可以使用AtomicInteger来将跟踪计数保持在ABQ中,就像LBQ一样。我们也可以为ABQ使用两个锁。
我偶然发现了类似的问题。 ArrayBlockingQueue uses a single lock for insertion and removal but LinkedBlockingQueue uses 2 separate locks

但是我不明白那个问题的答案。我需要帮助来理解如果使用两个锁来实现ABQ会出现的问题。
如果有人可以举一个可能失败的竞赛条件的例子,那将是一个很好的选择。
这个问题可以标记为重复,但实际上是在寻找更具描述性的答案。那将是很大的帮助。

我在http://pastebin.com/ZD1uFy7S处粘贴了代码。任何人都可以显示粘贴的代码中是否可能存在竞争条件。

最佳答案

根据定义,ArrayBlockingQueue会阻止在put()发生且其固定数组已满时等待空间变为可用。

可用空间是take()返回的元素。换句话说,固定数组中的元素将随着时间的推移而被重用。 put()必须将其项目写入数组中的特定位置。

另一方面,LinkedBlockingQueue是一个链表。在本次讨论中,假设您创建了一个有界的对象,只是使其与ArrayBlockingQueue更相似。尝试同一件事:

当LinkedBlockingQueue已满时,放置put()一个元素。它将等待元素变为可用。

但是在这种情况下,当您执行take()时,它将只是返回head值并核对该项目。然后put()会看到LinkedBlockingQueue低于容量。它将其项目链接到列表的末尾。没有像ArrayBlockingQueue这样的必须覆盖连续内存的覆盖。

编辑:这是一种假设的练习,因为代码不是以这种方式编写的。但是无论如何,这里有更多详细信息,尤其是insert和extract方法:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/ArrayBlockingQueue.java

如果使用了2个锁,则潜在的问题,并且现有代码或多或少保持不变:

ArrayBlockingQueue已满

线程1:调用take(),获取锁A,执行其操作,减量计为[capacity-1]-但尚未完成

线程2:调用put(),在T1仍在运行时获取锁B,将计数递增到[容量],释放锁B

线程1:信号notFull()

线程3:即使数组确实已满,put()也开始执行,但会覆盖一个元素,因为ArrayBlockingQueue使用循环增量。

这种情况不会在LinkedBlockingQueue中发生。

10-08 01:18