来自JavaDocs:
我有2个场景,一个需要队列支持许多生产者(使用它的线程)和一个消费者,另一个是另一种方式。
我不明白要使用哪种实现。有人可以解释一下这些差异是什么吗?
此外,ArrayBlockingQueue
中的“可选公平政策”是什么?
答案 0 :(得分:104)
ConcurrentLinkedQueue表示没有锁定(即没有同步(this)或Lock.lock调用)。它将在修改期间使用CAS - Compare and Swap操作来查看头/尾节点是否仍然与它开始时相同。如果是,则操作成功。如果头/尾节点不同,它会旋转并再试一次。
在进行任何修改之前,LinkedBlockingQueue将锁定。所以你的报价电话会阻止,直到他们获得锁定。您可以使用带有TimeUnit的商品重载来表示您只愿意在放弃添加之前等待X时间(通常适用于消息类型队列,其中消息在X毫秒后过时)。
公平意味着Lock实现将保持线程的顺序。意味着如果线程A进入然后线程B进入,则线程A将首先获得锁定。没有公平,真的不确定会发生什么。它很可能是下一个被安排的线程。
至于使用哪一个,取决于。我倾向于使用ConcurrentLinkedQueue,因为我的生产者花在工作上的时间是多种多样的。我没有很多生产商在同一时刻生产。但消费者方面更复杂,因为民意调查不会进入良好的睡眠状态。你必须亲自处理。
答案 1 :(得分:44)
基本上它们之间的区别在于性能特征和阻塞行为。
首先采用最简单的方法,ArrayBlockingQueue
是一个固定大小的队列。因此,如果将大小设置为10,并尝试插入第11个元素,则insert语句将阻塞,直到另一个线程删除元素。如果多个线程试图同时插入和删除(换句话说在阻塞队列期间)会发生公平性问题。公平算法确保请求的第一个线程是第一个得到的线程。否则,给定线程可能比其他线程等待更长时间,从而导致不可预测的行为(有时一个线程将花费几秒钟,因为之后开始的其他线程首先得到处理)。权衡是管理公平性需要管理费用,从而降低吞吐量。
LinkedBlockingQueue
和ConcurrentLinkedQueue
之间最重要的区别在于,如果您从LinkedBlockingQueue
请求一个元素并且队列为空,那么您的线程将一直等到那里有一些东西。 ConcurrentLinkedQueue
将立即返回空队列的行为。
哪一个取决于您是否需要阻止。你有很多生产者和一个消费者,听起来就像这样。另一方面,如果您有许多消费者而且只有一个生产者,您可能不需要阻止行为,并且可能很高兴让消费者检查队列是否为空并且如果是则继续前进。
答案 2 :(得分:8)
您的问题标题提及阻止队列。但是,ConcurrentLinkedQueue
不是阻塞队列。
BlockingQueue
是ArrayBlockingQueue
,DelayQueue
,LinkedBlockingDeque
,LinkedBlockingQueue
,PriorityBlockingQueue
和SynchronousQueue
。
其中一些显然不适合您的目的(DelayQueue
,PriorityBlockingQueue
和SynchronousQueue
)。 LinkedBlockingQueue
和LinkedBlockingDeque
是相同的,除了后者是双端队列(它实现了Deque接口)。
由于ArrayBlockingQueue
仅在您要限制元素数量时才有用,我会坚持LinkedBlockingQueue
。
答案 3 :(得分:4)
ArrayBlockingQueue具有较低的内存占用,它可以重用元素节点,而不像LinkedBlockingQueue那样必须为每个新插入创建一个LinkedBlockingQueue $ Node对象。
答案 4 :(得分:1)
SynchronousQueue
(取自另一个question) SynchronousQueue
更像是一种切换,而LinkedBlockingQueue
只允许一个元素。不同之处在于put()
对SynchronousQueue
的调用在相应的take()
调用之前不会返回,但LinkedBlockingQueue
的大小为put()
BlockingQueue
调用(到空队列)将立即返回。它本质上是LinkedBlockingQueue
实现,当你不想要一个队列时(你不想维护任何未决数据)。
LinkedList
(LinkedList
实现但不完全JDK实现public LinkedBlockingQueue(int capacity)
{
if (capacity < = 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node< E >(null); // Maintains a underlying linkedlist. ( Use when size is not known )
}
它使用静态内部类Node来维护元素之间的链接)LinkedBlockingQueue的构造函数
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
用于维护链接的节点类
public ArrayBlockingQueue(int capacity, boolean fair)
{
if (capacity < = 0)
throw new IllegalArgumentException();
this.items = new Object[capacity]; // Maintains a underlying array
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
3。 ArrayBlockingQueue(数组实现)
ArrayBlockingQueue的构造函数
ArrayBlockingQueue
恕我直言,LinkedBlockingQueue
和ArrayBlockingQueue
之间的最大差异很明显,构造函数1具有基础数据结构数组和其他linkedList 。
LinkedBlockingQueue
使用single-lock double condition algorithm,而{{1}}是“双锁队列”算法的变体,它有2个锁2个条件(takeLock,putLock)
答案 5 :(得分:0)
ConcurrentLinkedQueue是无锁的,LinkedBlockingQueue则不是。每次调用LinkedBlockingQueue.put()或LinkedBlockingQueue.take()时,都需要先获取锁。换句话说,LinkedBlockingQueue的并发性很差。如果您关心性能,请尝试使用ConcurrentLinkedQueue + LockSupport。