【问题标题】:What is the Difference between ArrayBlockingQueue and LinkedBlockingQueueArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别
【发布时间】:2013-08-22 08:33:33
【问题描述】:
  1. 什么情况下最好使用 ArrayBlockingQueue,什么时候最好使用 LinkedBlockingQueue?
  2. 如果 LinkedBlockingQueue 默认容量等于 MAX Integer,那么将其用作具有默认容量的 BlockingQueue 真的有帮助吗?

【问题讨论】:

  • 对于第 1 点,我想这与 ArrayList 与 LinkedList 的原因完全相同;)
  • A BlockingQueue 不仅在 put() 上阻塞。当队列为空时,它还会阻塞 take()。
  • @sp00m 但在队列中我们没有插入或删除之间的时间。所以没有像 ArrayList 和 LinkedList 那样的性能问题
  • @user2375176 我认为如果您可以估计队列的大小,那么 ArrayBlockingQueue 会更好。但是如果添加率变高,那么它会阻塞并减少对象通过
  • @JBNizet 实际上,您可以在基于数组的实现中使用开始和结束偏移量。当开始偏移量大于结束偏移量时,元素必须读取数组边界周围的环绕。所以在前面插入一个元素可以通过将它存储在数组的末尾并调整开始偏移量而不需要移位来完成。

标签: java blockingqueue blockingcollection


【解决方案1】:

ArrayBlockingQueue 由一个数组支持,该数组的大小在创建后将永远不会改变。将容量设置为Integer.MAX_VALUE 将创建一个空间成本高的大阵列。 ArrayBlockingQueue 总是有界的。

LinkedBlockingQueue 动态创建节点,直到达到capacity。默认为Integer.MAX_VALUE。使用如此大的容量并没有额外的空间成本。 LinkedBlockingQueue 是可选的。

【讨论】:

    【解决方案2】:

    ArrayBlockingQueue<E>LinkedBlockingQueue<E>BlockingQueue<E> 接口的常见实现。

    ArrayBlockingQueuearray 支持,QueueFIFO 执行命令。就时间而言,队列的头部是最老的元素,队列的尾部是最年轻的元素。 ArrayBlockingQueue 也是固定大小的有界缓冲区,另一方面 LinkedBlockingQueue 是一个可选的有界队列,构建在链接节点之上。

    可选的容量绑定构造函数参数用作防止队列过度扩展的一种方式,因为如果未指定容量,则它等于Integer.MAX_VALUE

    阅读更多来自here

    基准测试:http://www.javacodegeeks.com/2010/09/java-best-practices-queue-battle-and.html

    【讨论】:

    • 我怀疑 LinkedBlockingQueue 会有更高的吞吐量。有什么证据可以支持这一说法吗?
    • @EskoLuontola:您可以从这里找到基准:javacodegeeks.com/2010/09/…
    • 因此,基于该基准,LinkedBlockingQueue 在生产消费者场景中更快,但在前两个基准中,ArrayBlockingQueue 稍快一些。不管怎样,Disruptor 会用他们俩擦地板:code.google.com/p/disruptor/wiki/PerformanceResults
    【解决方案3】:

    ArrayBlockingQueue

    ArrayBlockingQueue 是一个有界的阻塞队列,它将元素内部存储在一个数组中。它是有界的意味着它不能存储无限数量的元素。它可以同时存储的元素数量有一个上限。您在实例化时设置上限,之后就无法更改。

    LinkedBlockingQueue

    LinkedBlockingQueue 将元素内部保持在链接结构(链接节点)中。如果需要,此链接结构可以选择具有上限。如果没有指定上限,则使用 Integer.MAX_VALUE 作为上限。

    相似性

    ArrayBlockingQueue/LinkedBlockingQueue 以 FIFO(先进先出)的顺序在内部存储元素。队列头是入队时间最长的元素,队列尾是入队时间最短的元素。

    区别

    • LinkedBlockingQueue 有一个 putLock 和一个 takeLock 分别用于插入和删除,但 ArrayBlockingQueue 仅使用 1 个锁。
    • ArrayBlockingQueue 使用单锁双条件算法,LinkedBlockingQueue 是“双锁队列”算法的变体,它有 2 个锁 2 个条件(takeLock、putLock)。

    LinkedBlockingQueue 实现使用了两个锁队列算法。因此 LinkedBlockingQueue 的 take 和 put 可以同时工作,但 ArrayBlockingQueue 不是这种情况。在 ArrayBlockingQueue 中使用单个锁的原因是,ArrayBlockingQueue 必须避免覆盖条目,以便它需要知道开始和结束的位置。 LinkedBlockQueue 不需要知道这一点,因为它让 GC 担心清理队列中的节点。

    【讨论】:

      【解决方案4】:

      向 ArrayBlockingQueue 添加元素应该更快,因为这意味着只设置对支持 Object 数组的元素的引用,而向 LinkedBlockingQueue 添加元素意味着创建一个节点并设置它的 item、prev 和 next 字段。此外,当我们从 LinkedBlockingQueue 中删除一个元素时,删除的节点会变成垃圾,这可能会影响应用程序的性能。

      至于内存消耗 ArrayBlockingQueue 总是保存一个满容量的 Object 数组,即使是空的。另一方面,LinkedBlockingQueue 中的一个元素是一个具有 3 个对象字段的对象的节点。

      【讨论】:

      • 这是一个很好的答案,可以解释原因,但是您提到 ArrayBlockingQueue 应该更快,根据您提供的原因,我同意您的看法。但是 Javadocs 说“链接队列通常比基于数组的队列具有更高的吞吐量,但在大多数并发应用程序中性能更不可预测。”见 LinkedBlockingQueue.class
      • 延迟和吞吐量是两个不同的东西。 ArrayBlockingQueue 具有更好的延迟,因为它可以更快地在数组中设置引用,而 LinkedBlockingQueue 具有更好的吞吐量,因为它使用 2 个差异锁进行 put 和 take 并且仅在边缘条件下同步。
      猜你喜欢
      • 1970-01-01
      • 2010-10-02
      • 2011-12-12
      • 2010-09-16
      • 2012-03-14
      • 2012-02-06
      • 2011-02-25
      • 2011-11-22
      • 2015-03-26
      相关资源
      最近更新 更多