我应该在Java中使用哪个并发队列实现?

Dav*_*ann 123 java queue concurrency multithreading

来自JavaDocs:

  • 的ConcurrentLinkedQueue是当许多线程共享访问一个共同的集合一个合适的选择.此队列不允许null元素.
  • ArrayBlockingQueue是一个经典的"有界缓冲区",其中固定大小的数组包含由生产者插入并由消费者提取的元素.此类支持用于排序等待生产者和消费者线程的可选公平策略
  • LinkedBlockingQueue通常具有比基于阵列的队列更高的吞吐量,但在大多数并发应用程序中具有较低的可预测性能.

我有两个场景,一个需要队列支持许多生产者(使用它的线程)与一个消费者,另一个是另一种方式.

我不明白使用哪种实现.有人可以解释一下这些差异是什么吗?

此外,什么是"可选的公平政策" ArrayBlockingQueue

Jus*_*udd 111

ConcurrentLinkedQueue表示不进行锁定(即没有同步(this)或Lock.lock调用).它将在修改期间使用CAS - 比较和交换操作来查看头/尾节点是否仍然与它开始时相同.如果是,则操作成功.如果头/尾节点不同,它将旋转并再次尝试.

LinkedBlockingQueue将在任何修改之前锁定.所以你的报价电话会阻止,直到他们获得锁定.您可以使用带有TimeUnit的商品重载来表示您只愿意在放弃添加之前等待X时间(通常适用于消息类型队列,其中消息在X毫秒之后失效).

公平意味着Lock实现将保持线程的顺序.意味着如果线程A进入然后线程B进入,则线程A将首先获得锁定.没有公平,真的不确定会发生什么.它很可能是下一个被安排的线程.

至于哪一个使用,取决于.我倾向于使用ConcurrentLinkedQueue,因为我的生产者将工作放到队列上的时间是多种多样的.我没有很多生产商在同一时刻生产.但消费者方面更复杂,因为民意调查不会进入良好的睡眠状态.你必须自己处理.

  • 什么意思 - “它会旋转并再试一次。” ? (2认同)

Yis*_*hai 50

基本上它们之间的区别在于性能特征和阻塞行为.

以最简单的方式,ArrayBlockingQueue是一个固定大小的队列.因此,如果将大小设置为10,并尝试插入第11个元素,则insert语句将阻塞,直到另一个线程删除元素.如果多个线程试图同时插入和删除(换句话说在阻塞队列期间)会发生公平性问题.公平算法确保请求的第一个线程是第一个得到的线程.否则,给定线程可能比其他线程等待更长时间,从而导致不可预测的行为(有时一个线程将花费几秒钟,因为之后开始的其他线程首先得到处理).权衡是管理公平性需要管理费用,减慢吞吐量.

LinkedBlockingQueue和之间最重要的区别ConcurrentLinkedQueue是,如果您从a请求一个元素LinkedBlockingQueue并且队列为空,那么您的线程将一直等到那里有一些东西.A ConcurrentLinkedQueue将立即返回空队列的行为.

哪一个取决于您是否需要阻止.你有很多生产者和一个消费者,听起来就像这样.另一方面,如果您有许多消费者而且只有一个生产者,您可能不需要阻止行为,并且可能很高兴让消费者检查队列是否为空并且如果是,则继续.

  • 答案具有误导性.LinkedBlockingQueue和ConcurrentLinkedQueue都有方法"poll()",它删除队列头或返回null(不阻塞)和方法"offer(E e)",它插入到队列的尾部并且不阻塞.不同之处在于,只有LinkedBlockingQueue对非阻塞操作具有阻塞操作* - 对于该特权,您需要支付LinkedBlockingQueue实际具有某种锁定的价格.另一个答案解释了这个. (58认同)

Pow*_*ord 8

你的问题标题提到阻止队列.但是,ConcurrentLinkedQueue阻塞队列.

BlockingQueues为ArrayBlockingQueue,DelayQueue,LinkedBlockingDeque,LinkedBlockingQueue,PriorityBlockingQueue,和SynchronousQueue.

有些显然是不适合你的目的(DelayQueue,PriorityBlockingQueue,和SynchronousQueue). LinkedBlockingQueue并且LinkedBlockingDeque是相同的,除了后者是双端队列(它实现了Deque接口).

因为ArrayBlockingQueue只有你想限制元素的数量才有用,我坚持LinkedBlockingQueue.