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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1301691/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:00:19  来源:igfitidea点击:

Which concurrent Queue implementation should I use in Java?

javamultithreadingconcurrencyqueue

提问by David Hofmann

From the JavaDocs:

来自 JavaDocs:

  • A ConcurrentLinkedQueueis an appropriate choice when many threads will share access to a common collection. This queue does not permit null elements.
  • ArrayBlockingQueueis a classic "bounded buffer", in which a fixed-sized array holds elements inserted by producers and extracted by consumers. This class supports an optional fairness policy for ordering waiting producer and consumer threads
  • LinkedBlockingQueuetypically have higher throughput than array-based queues but less predictable performance in most concurrent applications.
  • 的ConcurrentLinkedQueue是当许多线程共享访问一个共同的集合一个合适的选择。此队列不允许空元素。
  • ArrayBlockingQueue是一个经典的“有界缓冲区”,其中一个固定大小的数组保存由生产者插入并由消费者提取的元素。此类支持用于排序等待生产者和消费者线程的可选公平策略
  • LinkedBlockingQueue通常比基于数组的队列具有更高的吞吐量,但在大多数并发应用程序中的可预测性较差。

I have 2 scenarios, one requires the queue to support many producers (threads using it) with one consumer and the other is the other way around.

我有两种情况,一种要求队列支持多个生产者(使用它的线程)和一个消费者,另一种情况正好相反。

I do not understand which implementation to use. Can somebody explain what the differences are?

我不明白要使用哪种实现。有人可以解释一下有什么区别吗?

Also, what is the 'optional fairness policy' in the ArrayBlockingQueue?

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

采纳答案by Yishai

Basically the difference between them are performance characteristics and blocking behavior.

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

Taking the easiest first, ArrayBlockingQueueis a queue of a fixed size. So if you set the size at 10, and attempt to insert an 11th element, the insert statement will block until another thread removes an element. The fairness issue is what happens if multiple threads try to insert and remove at the same time (in other words during the period when the Queue was blocked). A fairness algorithm ensures that the first thread that asks is the first thread that gets. Otherwise, a given thread may wait longer than other threads, causing unpredictable behavior (sometimes one thread will just take several seconds because other threads that started later got processed first). The trade-off is that it takes overhead to manage the fairness, slowing down the throughput.

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

The most important difference between LinkedBlockingQueueand ConcurrentLinkedQueueis that if you request an element from a LinkedBlockingQueueand the queue is empty, your thread will wait until there is something there. A ConcurrentLinkedQueuewill return right away with the behavior of an empty queue.

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

Which one depends on if you need the blocking. Where you have many producers and one consumer, it sounds like it. On the other hand, where you have many consumers and only one producer, you may not need the blocking behavior, and may be happy to just have the consumers check if the queue is empty and move on if it is.

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

回答by Powerlord

Your question title mentions Blocking Queues. However, ConcurrentLinkedQueueis nota blocking queue.

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

The BlockingQueues are ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, PriorityBlockingQueue, and SynchronousQueue.

BlockingQueues为ArrayBlockingQueueDelayQueueLinkedBlockingDequeLinkedBlockingQueuePriorityBlockingQueue,和SynchronousQueue

Some of these are clearly not fit for your purpose (DelayQueue, PriorityBlockingQueue, and SynchronousQueue). LinkedBlockingQueueand LinkedBlockingDequeare identical, except that the latter is a double-ended Queue (it implements the Deque interface).

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

Since ArrayBlockingQueueis only useful if you want to limit the number of elements, I'd stick to LinkedBlockingQueue.

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

回答by Justin Rudd

ConcurrentLinkedQueuemeans no locks are taken (i.e. no synchronized(this) or Lock.lockcalls). It will use a CAS - Compare and Swapoperation during modifications to see if the head/tail node is still the same as when it started. If so, the operation succeeds. If the head/tail node is different, it will spin around and try again.

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

LinkedBlockingQueuewill take a lock before any modification. So your offer calls would block until they get the lock. You can use the offer overload that takes a TimeUnit to say you are only willing to wait X amount of time before abandoning the add (usually good for message type queues where the message is stale after X number of milliseconds).

LinkedBlockingQueue将在任何修改之前锁定。因此,您的要约调用将阻塞,直到他们获得锁定为止。您可以使用采用 TimeUnit 的提供重载来表示您只愿意在放弃添加之前等待 X 时间(通常适用于消息在 X 毫秒后过时的消息类型队列)。

Fairness means that the Lock implementation will keep the threads ordered. Meaning if Thread A enters and then Thread B enters, Thread A will get the lock first. With no fairness, it is undefined really what happens. It will most likely be the next thread that gets scheduled.

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

As for which one to use, it depends. I tend to use ConcurrentLinkedQueuebecause the time it takes my producers to get work to put onto the queue is diverse. I don't have a lot of producers producing at the exact same moment. But the consumer side is more complicated because poll won't go into a nice sleep state. You have to handle that yourself.

至于用哪一种,看情况。我倾向于使用ConcurrentLinkedQueue,因为我的生产者将工作放入队列所花费的时间是多种多样的。我没有很多生产者同时生产。但是消费者方面更复杂,因为 poll 不会进入良好的睡眠状态。你必须自己处理。

回答by Deng

ArrayBlockingQueue has lower memory footprint, it can reuse element node, not like LinkedBlockingQueue that have to create a LinkedBlockingQueue$Node object for each new insertion.

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

回答by Vipin

  1. SynchronousQueue( Taken from another question)
  1. SynchronousQueue(摘自另一个问题

SynchronousQueueis more of a handoff, whereas the LinkedBlockingQueuejust allows a single element. The difference being that the put()call to a SynchronousQueuewill not return until there is a corresponding take()call, but with a LinkedBlockingQueueof size 1, the put()call (to an empty queue) will return immediately. It's essentially the BlockingQueueimplementation for when you don't really want a queue (you don't want to maintain any pending data).

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

  1. LinkedBlockingQueue(LinkedListImplementation but Not Exactly JDK Implementation of LinkedListIt uses static inner class Node to maintain Links between elements )
  1. LinkedBlockingQueueLinkedList实现但不完全是JDK实现LinkedList它使用静态内部类Node来维护元素之间的链接)

Constructor for LinkedBlockingQueue

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

Node class Used to Maintain Links

用于维护链接的节点类

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

3 . ArrayBlockingQueue ( Array Implementation )

3 . ArrayBlockingQueue(数组实现)

Constructor for 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 Biggest Difference between ArrayBlockingQueueand LinkedBlockingQueueis clear from constructor one has underlying data structure Array and other linkedList.

恕我直言ArrayBlockingQueueLinkedBlockingQueue从构造函数中可以清楚地看出两者之间的最大区别是具有底层数据结构 Array 和其他 linkedList

ArrayBlockingQueueuses single-lock double condition algorithmand LinkedBlockingQueueis variant of the "two lock queue" algorithm and it has 2 locks 2 conditions ( takeLock , putLock)

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

回答by user319609

ConcurrentLinkedQueue is lock-free, LinkedBlockingQueue is not. Every time you invoke LinkedBlockingQueue.put() or LinkedBlockingQueue.take(), you need acquire the lock first. In other word, LinkedBlockingQueue has poor concurrency. If you care performance, try ConcurrentLinkedQueue + LockSupport.

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