我的问题涉及 这个问题 早些时候问过。在我使用队列在生产者线程和消费者线程之间进行通信的情况下,人们通常建议使用 LinkedBlockingQueue 或者 ConcurrentLinkedQueue?

与另一种相比,使用一种的优点/缺点是什么?

从 API 的角度来看,我看到的主要区别是 LinkedBlockingQueue 可以选择性地有界。

有帮助吗?

解决方案

对于生产者/消费者线程,我不确定 ConcurrentLinkedQueue 甚至是一个合理的选择 - 它没有实现 BlockingQueue, ,这是 IMO 生产者/消费者队列的基本接口。你必须打电话 poll(), ,如果你没有找到任何东西,请稍等一下,然后再次轮询等等......当新物品进入时会导致延迟,而当物品为空时会导致效率低下(由于不必要地从睡眠中醒来)。

来自 BlockingQueue 的文档:

BlockingQueue 实现设计主要用于生产者-消费者队列

我知道它不会 严格地 说生产者-消费者队列只应使用阻塞队列,但即便如此......

其他提示

这个问题值得更好的回答。

爪哇的 ConcurrentLinkedQueue 是基于著名的 算法由 Maged M 提供。迈克尔和迈克尔·L.斯科特 为了 非阻塞无锁 队列。

“非阻塞”作为竞争资源(我们的队列)的术语意味着无论平台的调度程序做什么,例如中断线程,或者如果相关线程太慢,其他线程都会竞争相同的资源仍然能够进步。例如,如果涉及锁,则持有锁的线程可能会被中断,并且等待该锁的所有线程都将被阻塞。本质锁( synchronized Java 中的关键字)也会带来严重的性能损失 - 就像当 偏向锁定 涉及并且确实存在争用,或者在虚拟机决定在旋转宽限期后“膨胀”锁并阻止竞争线程之后...这就是为什么在许多情况下(低/中争用的场景),对原子引用进行比较和设置可以更加有效,这正是许多非阻塞数据结构正在做的事情。

爪哇的 ConcurrentLinkedQueue 不仅是非阻塞的,而且它具有生产者不与消费者竞争的令人敬畏的特性。在单一生产者/单一消费者场景(SPSC)中,这实际上意味着不会有争用可言。在多生产者/单消费者场景中,消费者不会与生产者竞争。当多个生产者尝试时,该队列确实存在争用 offer(), ,但这就是定义上的并发。它基本上是一个通用且高效的非阻塞队列。

至于它不是一个 BlockingQueue, 嗯,阻塞线程在队列中等待是设计并发系统的一种极其糟糕的方式。不。如果您不知道如何使用 ConcurrentLinkedQueue 在消费者/生产者场景中,然后只需切换到更高级别的抽象,例如良好的参与者框架。

LinkedBlockingQueue 当队列为空或已满并且相应的消费者/生产者线程进入睡眠状态时,会阻塞消费者或生产者。但这种阻止功能是有代价的:每个 put 或 take 操作都在生产者或消费者(如果有很多)之间进行锁竞争,因此在有许多生产者/消费者的情况下,操作可能会更慢。

ConcurrentLinkedQueue 没有使用锁,但是 中科院, ,其 put/take 操作可能会减少与许多生产者和消费者线程的争用。但作为一个“免费等待”的数据结构, ConcurrentLinkedQueue 空时不会阻塞,这意味着消费者需要处理 take() 返回 null 例如,消费者线程占用 CPU。

因此,哪一个“更好”取决于消费者线程的数量、它们消费/生产的速率等。每个场景都需要一个基准。

一个特定的用例,其中 ConcurrentLinkedQueue 显然更好的是生产者首先生产一些东西并通过将工作放入队列来完成他们的工作 并且只有在之后 消费者开始消费,知道当队列为空时他们就会完成。(这里没有生产者-消费者之间的并发,只有生产者-生产者和消费者-消费者之间的并发)

另一个解决方案(扩展性不佳)是集合通道:java.util.concurrent同步队列

如果您的队列不可扩展并且仅包含一个生产者/消费者线程。您可以使用无锁队列(不需要锁定数据访问)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top