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

2022-08-31 07:40:01

来自 JavaDocs:

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

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

我不知道要使用哪个实现。有人能解释一下它们有什么区别吗?

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


答案 1

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

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

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

至于使用哪一个,那就要视情况而定。我倾向于使用 ConcurrentLinkedQueue,因为我的生产者将工作放到队列中所需的时间是多种多样的。我没有很多制片人在同一时刻生产。但消费者方面更复杂,因为民意调查不会进入良好的睡眠状态。你必须自己处理。


答案 2

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

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

和 之间最重要的区别是,如果您从 中请求元素并且队列为空,则线程将等到那里有某些内容。A 将立即返回空队列的行为。LinkedBlockingQueueConcurrentLinkedQueueLinkedBlockingQueueConcurrentLinkedQueue

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


推荐