什么时候更喜欢
LinkedBlockingQueue
而不是ArrayBlockingQueue
?
当以下情况时,在
LinkedBlockingQueue
和 ArrayBlockingQueue
中使用哪种数据结构:
虽然有类似的问题,但它并没有强调哪个应该是首选的事实?
链接:
蜘蛛鲍里斯已经概述了
ArrayBlockingQueue
和 LinkedBlockingQueue
之间最明显的区别 - 前者总是有界的,而后者可以是无界的。
因此,如果您需要无界阻塞队列,
LinkedBlockingQueue
或用作 LinkedTransferQueue
的 BlockingQueue
是 java.util.concurrent
工具箱中的最佳选择。
但是假设您需要一个有界阻塞队列。 最后,您应该根据对实际工作负载的模拟进行大量实验来选择实施方案。 尽管如此,这里有一些注释可以帮助您做出选择或解释实验结果:
ArrayBlockingQueue
可以使用可配置(开/关)调度公平策略来创建。如果您需要公平性或想要避免生产者/消费者饥饿,这非常有用,但它会降低您的吞吐量。ArrayBlockingQueue
预先分配其后备数组,因此它在使用期间不会分配节点,但它会立即占用相当大的内存块,如果内存碎片,这可能会成为问题。ArrayBlockingQueue
性能变化应该较小,因为它总体上移动部件较少,它使用更简单且不太复杂的单锁算法,它在使用过程中不会创建节点,并且其缓存行为应该相当一致。LinkedBlockingQueue
应该有更好的吞吐量,因为它对头部和尾部使用单独的锁。LinkedBlockingQueue
不预先分配节点,这意味着它的内存占用将大致与其大小相匹配,但这也意味着它将产生一些分配和释放节点的工作。LinkedBlockingQueue
可能会有更差的缓存行为,这可能会影响其自身的性能,而且还会由于错误共享而影响其他组件的性能。根据您的用例以及您对性能的关心程度,您可能还想看看
java.util.concurrent
之外的内容并考虑 Disruptor (一种速度非常快,但有些专业的有界非阻塞环形缓冲区)或 JCTools (根据生产者和消费者的数量,具有不同保证的各种有界或无界队列)。
来自 JavaDoc for
ArrayBlockingQueue
由数组支持的有界阻塞队列。
强调我的
来自 JavaDoc for
LinkedBlockingQueue
:
基于链接节点的可选有界阻塞队列。
强调我的
因此,如果您需要一个有界队列,您可以使用其中一个,如果您需要一个无界队列,您必须使用
LinkedBlockingQueue
。
对于有界队列,那么您需要进行基准测试以确定哪个更好。
虽然 ArrayBlockingQueue 总体上更简单,但我相信它对 put 和 take 操作都使用单个锁。因此,如果您使用它来传输非常频繁(例如每秒数千或数百万条消息)消息从一个线程到另一个线程,则可能会因争用而导致性能更差。
相反,我认为 LinkedBlockingQueue 使用独立的锁来进行 put 和 take。因此,如果只有一个线程放入,另一个线程取出,则争用可能会较少。但是,如果您有多个线程放入或多个线程取出,则可能会出现更多争用,因为每个锁定操作都会比 ArrayBockingQueue 的等效操作长一点。
结论:如果您使用它频繁地将消息从单个源线程传输到单个目标线程,那么 LinkedBlockingQueue 可能会更好,因为它可能具有更少的争用。否则 ArrayBlockingQueue 可能会稍微快一些。
如果有疑问,您必须针对您的特定用例进行实际测试。但是,除非您尝试每秒发送数百万条消息,否则您可能不会注意到任何显着差异 - 在大多数情况下,两者都同样有效:)