LinkedBlockingQueue
还是ConcurrentLinkedQueue
?从使用中的优缺点来说,它们各有千秋。
就API层面而言,主要区别在于
LinkedBlockingQueue
可以选择性地设定上限。LinkedBlockingQueue
还是ConcurrentLinkedQueue
?LinkedBlockingQueue
可以选择性地设定上限。对于生产者/消费者线程,我不确定 ConcurrentLinkedQueue
是否是一个合理的选择 - 它没有实现 BlockingQueue
,而这是我认为生产者/消费者队列的基本接口。你需要调用 poll()
,如果没有找到任何内容,则稍等片刻再次轮询等待新项目进来,从而导致延迟,并且当它为空时效率低下(由于从睡眠中不必要地唤醒)。
从 BlockingQueue 文档中可以看到:
BlockingQueue
的实现主要设计用于生产者-消费者队列。
我知道它并没有严格说明只有阻塞队列才应该用于生产者/消费者队列,但即便如此,还是应该考虑使用阻塞队列。
ConcurrentLinkedQueue
基于著名的Maged M. Michael和Michael L. Scott的算法,用于非阻塞无锁队列。synchronized
关键字)在性能方面也可能带来严重的惩罚——例如当涉及biased locking并且存在争用时,或者在VM决定在自旋优雅期间“膨胀”锁并阻止竞争线程之后……因此,在许多情况下(低/中等争用场景),对原子引用进行比较和设置可以更加高效,这正是许多非阻塞数据结构所做的。LinkedBlockingQueue
队列为空或已满时,相应的消费者/生产者线程会被阻塞。但这种阻塞特性是有代价的:每个put或take操作在生产者或消费者(如果有多个)之间存在锁竞争,因此在具有许多生产者/消费者的场景中,操作可能会变慢。
ConcurrentLinkedQueue
不使用锁,而是使用CAS进行其添加/轮询操作,可能会减少许多生产者和消费者线程之间的竞争。但作为一种“无等待”的数据结构,ConcurrentLinkedQueue
在空时不会阻塞,这意味着消费者将需要通过“繁忙等待”来处理poll()
返回的null
值,例如消费者线程占用CPU。
因此,哪一个更好取决于消费者线程的数量、它们的生产/消费速率等。每种情况都需要进行基准测试。
有一个特定的用例,ConcurrentLinkedQueue
明显更好的情况是当生产者首先生产某些东西,并通过将工作放入队列来完成其工作,只有在消费者开始消耗时,才知道他们会在队列为空时完成。(这里没有生产者-消费者之间的并发,但只有生产者-生产者和消费者-消费者之间的并发)
ConcurrentLinkedQueue.poll使用CAS来维护线程安全性。
LinkedBlockingQueue.poll使用ReentrantLock!因此它更慢。但提供阻塞功能。
ConcurrentLinkedQueue只是一个线程安全的链表。
ConcurrentLinkedQueue
也非常有用。例如,在多租户服务器中。假设出于隔离原因,您不使用单个阻塞队列和租户鉴别器。 - LateralFractaltake()
和put()
仅比ConcurrentLinkedQueue
消耗更多的资源(在同步方面)。尽管如此,在生产者-消费者场景中使用有界队列是最好的选择。 - amarnath harish