Java Queue的实现,哪一个?

来自Javadoc:

  • ConcurrentLinkedQueue是许multithreading将共享访问共享集合的合适select。 该队列不允许空元素。
  • ArrayBlockingQueue是一个经典的“有界缓冲区”,其中一个固定大小的数组包含生产者插入的元素,并由消费者提取。 这个类支持一个可选的公平策略来sorting等待的生产者和消费者线程
  • LinkedBlockingQueue通常比基于arrays的队列具有更高的吞吐量,但是在大多数并发应用程序中性能较差。

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

我不明白是否应该使用ConcurrentLikedQueue或其他(数组或LinkedList实现)。 Wherent'所有这些实现应该是并发的? 我的意思是,有人可以解释我ConcurrentLikedQueueLinkedBlockingQueue什么区别吗?

另外, ArrayBlockingQueue的可选公平策略是什么?

基本上它们之间的差别是性能特征和阻塞行为。

最简单的是,ArrayBlockingQueue是一个固定大小的队列。 因此,如果将大小设置为10,并尝试插入第11个元素,则插入语句将阻塞,直到另一个线程删除元素。 公平问题是如果多个线程同时插入和删除(换句话说,在队列被阻塞期间)会发生什么情况。 公平algorithm确保询问的第一个线程是获取的第一个线程。 否则,给定的线程可能会比其他线程等待更长的时间,导致不可预知的行为(有时一个线程将花费几秒钟的时间,因为稍后开始处理的其他线程会先被处理)。 权衡是pipe理公平性花费开销,放慢吞吐量。

LinkedBlockingQueue和ConcurrentLinkedQueue最重要的区别在于,如果您从LinkedBlockingQueue请求一个元素,并且该队列是空的,那么您的线程将一直等待,直到有什么东西出现为止。 ConcurrentLinkedQueue将立即返回一个空队列的行为。

哪一个取决于你是否需要阻塞。 如果你有很多生产者和消费者,听起来就像是这样。 另一方面,如果你有很多消费者,只有一个生产者,你可能不需要阻塞行为,只要消费者检查队列是否为空并继续前进就可能会很高兴。

ConcurrentLinkedQueue意味着没有锁(即没有同步(this)或Lock.lock调用)。 它将在修改期间使用CAS – 比较和交换操作来查看头部/尾部节点是否仍然与启动时相同。 如果是,则操作成功。 如果头部/尾部节点不同,则会旋转并重试。

LinkedBlockingQueue将在任何修改之前locking。 所以你的报价电话会阻止,直到他们locking。 您可以使用带有TimeUnit的报价重载,表示您在放弃添加之前只愿意等待X个时间量(通常对于X毫秒后消息是陈旧的消息types队列而言是好的)。

公平性意味着Lock实现将保持线程的有序性。 这意味着如果线程A进入,然后线程B进入,线程A将首先获得锁。 没有公正,事实上是不确定的。 它很可能是下一个预定的线程。

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

您的问题标题提到了阻止队列。 但是, ConcurrentLinkedQueue 不是阻塞队列。

BlockingQueueArrayBlockingQueueDelayQueueDelayQueueDelayQueuePriorityBlockingQueueSynchronousQueue

其中一些显然不适合您的目的( DelayQueuePriorityBlockingQueueSynchronousQueue )。 LinkedBlockingQueueLinkedBlockingDeque是相同的,只不过后者是一个双端队列(它实现了Deque接口)。

由于ArrayBlockingQueue只在你想限制元素的数量时才有用,所以我会坚持LinkedBlockingQueue

ArrayBlockingQueue具有较低的内存占用,它可以重用元素节点,而不像LinkedBlockingQueue那样必须为每个新插入创build一个LinkedBlockingQueue $ Node对象。

  1. SynchronousQueue(取自另一个问题 )

SynchronousQueue更像是一个切换,而LinkedBlockingQueue只允许一个元素。 不同之处在于,调用SynchronousQueue的put()调用将不会返回,直到出现相应的take()调用,但LinkedBlockingQueue的大小为1时,put()调用(将返回空队列)将立即返回。 它基本上是BlockingQueue实现,当你不需要一个队列(你不想维护任何未决的数据)。

2。 LinkedBlockingQueue(LinkedList的实现,但不完全JDK的LinkedList实现它使用静态内部类节点维护元素之间的链接)

LinkedBlockingQueue的构造函数

 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 ) } 

节点类用于维护链接

 static class Node<E> { E item; Node<E> next; Node(E x) { item = x; } } 

3。 ArrayBlockingQueue(数组实现)

ArrayBlockingQueue的构造函数

 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(); } 

恕我直言,最大的ArrayBlockingQueue和LinkedBlockingQueue之间的差异是从构造函数清楚一个有基础数据结构数组和其他linkedList

ArrayBlockingQueue使用单锁双条件algorithm ,LinkedBlockingQueue是“双锁队列”algorithm的变体,它有2个锁2条件(takeLock,putLock)

ConcurrentLinkedQueue是无锁的,LinkedBlockingQueue不是。 每次调用LinkedBlockingQueue.put()或LinkedBlockingQueue.take()时,都需要先获取locking。 换句话说,LinkedBlockingQueue并发性差。 如果您关心性能,请尝试使用ConcurrentLinkedQueue + LockSupport。