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


132

从JavaDocs:

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

我有两种情况,一种情况要求队列支持一个使用者使用许多生产者(使用它的线程),而另一种情况则相反。

我不知道要使用哪种实现。有人可以解释这些区别是什么吗?

另外,什么是“可选的公平政策” ArrayBlockingQueue


1
您还忘记询问PriorityBlockingQueue,它对于指定处理线程的顺序很有用。
IgorGanapolsky 2014年

Answers:


53

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

最简单的首先ArrayBlockingQueue是固定大小的队列。因此,如果将大小设置为10,并尝试插入第11个元素,则insert语句将阻塞,直到另一个线程删除该元素。公平问题是,如果多个线程试图同时插入和删除(换句话说,在阻塞队列期间),将会发生什么。公平算法确保发出请求的第一个线程是获得的第一个线程。否则,给定线程的等待时间可能会比其他线程更长,从而导致无法预料的行为(有时一个线程将只需要几秒钟,因为稍后启动的其他线程会先被处理)。折衷方案是管理公平性需要开销,从而减慢了吞吐量。

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

哪一个取决于您是否需要阻止。在您有许多生产者和一个消费者的地方,听起来像是。另一方面,在您有许多使用者且只有一个生产者的情况下,您可能不需要阻塞行为,并且可能很高兴让使用者检查队列是否为空并继续前进。


67
答案具有误导性。LinkedBlockingQueue和ConcurrentLinkedQueue都具有删除队列开头或返回null(不阻塞)的方法“ poll()”和插入队列尾部且不阻塞的方法“ offer(E e)”。区别在于,除了非阻塞操作之外,只有LinkedBlockingQueue具有阻塞操作-并且,对于该特权,您要付出LinkedBlockingQueue实际上具有一定锁定的代价。另一个答案对此进行了解释。
赤裸裸的

123

ConcurrentLinkedQueue表示不执行任何锁定(即,不进行任何同步(this)或Lock.lock调用)。在修改期间,它将使用CAS-比较和交换操作来查看头/尾节点是否仍与启动时相同。如果是这样,则操作成功。如果头/尾节点不同,它将旋转并重试。

LinkedBlockingQueue将在进行任何修改之前先锁定。因此,您的报价请求将被阻止,直到获得锁定为止。您可以使用需要TimeUnit的商品重载来表示您只愿意等待X数量的时间再放弃添加(通常适用于X毫秒后消息已过期的消息类型队列)。

公平意味着锁定实现将保持线程有序。这意味着如果线程A进入,然后线程B进入,则线程A将首先获得锁。不公平地说,究竟发生什么是不确定的。它很可能是被调度的下一个线程。

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


1
在什么条件下ArrayBlockingQueue比LinkedBlockingQueue更好?
kolobok 2012年

@akapelko ArrayBlockingQueue允许更细粒度的排序。
IgorGanapolsky 2014年

2
这是什么意思-“它将旋转并重试。” ?
Lester

9

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

BlockingQueues为ArrayBlockingQueueDelayQueueLinkedBlockingDequeLinkedBlockingQueuePriorityBlockingQueue,和SynchronousQueue

有些显然是不适合你的目的(DelayQueuePriorityBlockingQueue,和SynchronousQueue)。 LinkedBlockingQueueLinkedBlockingDeque相同,除了后者是双端队列(它实现Deque接口)。

由于ArrayBlockingQueue仅在您要限制元素数量时才有用,因此我坚持使用LinkedBlockingQueue


我从标题中删除了阻止词,谢谢。让我看看是否知道,您的意思是说LinkedBlockingQueue可以在同一对象的多个使用者/生产方案中使用?
David Hofmann,

1
我以为ArrayBlockingQueue允许对线程进行更细粒度的排序?因此,它的优势。
IgorGanapolsky 2014年

4

ArrayBlockingQueue具有较低的内存占用量,它可以重用元素节点,与LinkedBlockingQueue不同,后者必须为每个新插入创建一个LinkedBlockingQueue $ Node对象。


1
好点子!我更喜欢ArrayBlockingQueue,而不是LinkedBlockingQueue
万亿美元

2
这不一定是正确的-如果您的队列在很多时候都快要排空了,但是需要能够变大,则ArrayBlockingQueue内存占用会更差-在整个时间段内,它仍然在内存中分配了一个大数组在LinkedBlockingQueue将有着不可忽视的内存占用量接近借此空当。
Krease

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

SynchronousQueue是更多的交接,而LinkedBlockingQueue正义只允许一个元素。区别在于,put()对a 的调用SynchronousQueue将在有相应的take()调用之前不会返回,但是LinkedBlockingQueue大小为1的put()调用(对空队列)将立即返回。实际上,它是BlockingQueue当您不需要队列(您不想维护任何待处理数据)时的实现。

  1. LinkedBlockingQueueLinkedList实现但并非完全是LinkedList它的JDK实现使用静态内部类Node维护元素之间的链接)

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

之间IMHO最大的区别ArrayBlockingQueue并且LinkedBlockingQueue是从一个构造已清楚底层数据结构阵列和其他链表

ArrayBlockingQueue使用单锁双重条件算法,并且LinkedBlockingQueue是“两个锁队列”算法的变体,它具有2个锁2个条件(takeLock,putLock)


0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.