来自JavaDocs:
-
当许多线程共享对公共集合的访问权时,ConcurrentLinkedQueue是一个合适的选择 . 此队列不允许null元素 .
-
ArrayBlockingQueue是一个经典的"bounded buffer",其中固定大小的数组包含由 生产环境 者插入并由消费者提取的元素 . 此类支持用于排序等待 生产环境 者和消费者线程的可选公平策略
-
LinkedBlockingQueue通常具有比基于阵列的队列更高的吞吐量,但在大多数并发应用程序中具有较低的可预测性能 .
我有两个场景,一个需要队列支持许多 生产环境 者(使用它的线程)与一个消费者,另一个是另一种方式 .
我不明白使用哪种实现 . 有人可以解释一下这些差异是什么吗?
另外, ArrayBlockingQueue
中的'optional fairness policy'是什么?
6 回答
基本上它们之间的区别在于性能特征和阻塞行为 .
首先采用最简单的方法,
ArrayBlockingQueue
是一个固定大小的队列 . 因此,如果将大小设置为10,并尝试插入第11个元素,则insert语句将阻塞,直到另一个线程删除元素 . 如果多个线程试图同时插入和删除(换句话说在阻塞队列期间)会发生公平性问题 . 公平算法确保请求的第一个线程是第一个得到的线程 . 否则,给定线程可能比其他线程等待更长时间,从而导致不可预测的行为(有时一个线程将花费几秒钟,因为之后开始的其他线程首先得到处理) . 权衡是管理公平性需要管理费用,减慢吞吐量 .LinkedBlockingQueue
和ConcurrentLinkedQueue
之间最重要的区别是,如果您从LinkedBlockingQueue
请求一个元素并且队列为空,那么您的线程将一直等到那里有一些东西 .ConcurrentLinkedQueue
将立即返回空队列的行为 .哪一个取决于您是否需要阻止 . 你有很多 生产环境 者和一个消费者,听起来就像这样 . 另一方面,如果您有许多消费者而且只有一个 生产环境 者,您可能不需要阻止行为,并且可能很高兴让消费者检查队列是否为空并且如果是,则继续 .
ConcurrentLinkedQueue表示没有锁定(即没有同步(this)或Lock.lock调用) . 它将在修改期间使用CAS - Compare and Swap操作,以查看头/尾节点是否仍然与启动时相同 . 如果是,则操作成功 . 如果头/尾节点不同,它将旋转并再次尝试 .
LinkedBlockingQueue将在进行任何修改之前锁定 . 所以你的报价电话会阻止,直到他们获得锁定 . 您可以使用带有TimeUnit的商品重载来表示您只愿意在放弃添加之前等待X时间(通常适用于消息类型队列,其中消息在X毫秒之后失效) .
公平意味着Lock实现将保持线程的顺序 . 意味着如果线程A进入然后线程B进入,则线程A将首先获得锁定 . 没有公平,真的不确定会发生什么 . 它很可能是下一个被安排的线程 .
至于哪一个使用,取决于 . 我倾向于使用ConcurrentLinkedQueue因为我的 生产环境 者花时间投入队列的时间是多种多样的 . 我没有进入一个良好的睡眠状态 . 你必须自己处理 .
你的问题 Headers 提到阻止队列 . 但是,
ConcurrentLinkedQueue
是 not 阻塞队列 .BlockingQueue s是
ArrayBlockingQueue
,DelayQueue
,LinkedBlockingDeque
,LinkedBlockingQueue
,PriorityBlockingQueue
和SynchronousQueue
.其中一些显然不适合您的目的(
DelayQueue
,PriorityBlockingQueue
和SynchronousQueue
) .LinkedBlockingQueue
和LinkedBlockingDeque
是相同的,除了后者是双端队列(它实现了Deque接口) .由于
ArrayBlockingQueue
仅在您想限制元素数量时才有用,我会坚持LinkedBlockingQueue
.ArrayBlockingQueue具有较低的内存占用,它可以重用元素节点,而不像LinkedBlockingQueue那样必须为每个新插入创建一个LinkedBlockingQueue $ Node对象 .
SynchronousQueue
(取自另一个question)SynchronousQueue
更像是一种切换,而LinkedBlockingQueue
只允许一个元素 . 区别在于put()
调用SynchronousQueue
在相应的take()
调用之前不会返回,但是如果LinkedBlockingQueue
的大小为1,则put()
调用(到空队列)将立即返回 . 它实质上是BlockingQueue
实现,当你想要维护任何未决数据时 .LinkedBlockingQueue
(LinkedList
实现但并非完全JDK实现LinkedList
它使用静态内部类Node来维护元素之间的链接)LinkedBlockingQueue的构造函数
用于维护链接的节点类
3 . ArrayBlockingQueue(数组实现)
ArrayBlockingQueue的构造函数
恕我直言
ArrayBlockingQueue
和LinkedBlockingQueue
之间最大的区别很明显,构造函数有 underlying data structure Array and other linkedList .ArrayBlockingQueue
使用single-lock double condition algorithm和LinkedBlockingQueue
是"two lock queue"算法的变体,它有2个锁2个条件(takeLock,putLock)ConcurrentLinkedQueue是无锁的,LinkedBlockingQueue则不是 . 每次调用LinkedBlockingQueue.put()或LinkedBlockingQueue.take()时,都需要先获取锁 . 换句话说,LinkedBlockingQueue的并发性很差 . 如果您关心性能,请尝试使用ConcurrentLinkedQueue LockSupport .