队列根据其定义应该是FIFO类型的结构。虽然我们将其设为阻塞,但这意味着当队列的大小等于队列大小的MAX_LIMIT时,添加新元素时可能会阻塞几个线程。现在,如果一个元素从队列中退出,我们如何确保第一次等待的线程能够执行。
如果您阅读特定实现的文档,您会发现:
-
ArrayBlockingQueue
此类支持可选的公平性策略,用于订购等待的生产者和消费者线程。默认情况下,不保证此订购。然而,公平性设置为
true
的队列按照FIFO顺序授予线程访问权限。公平通常会降低吞吐量,但会降低可变性并避免饥饿。 -
LinkedBlockingQueue
没有公平保障。
-
SynchronousQueue
此类支持可选的公平性策略,用于订购等待的生产者和消费者线程。默认情况下,不保证此订购。然而,公平性设置为
true
的队列按照FIFO顺序授予线程访问权限。
有关常规队列类如何处理此问题的摘要,请参阅@Andreas的回答。
但我将提出另一种看待这一问题的方法。
您提出了一种场景,其中线程由于无法添加到队列而被阻塞。如果发生这种情况,那么从性能角度来看,最大的问题是被阻塞线程使用/持有的资源和锁。
一般来说,有两个可能的原因:
-
添加和删除队列条目的速率之间存在短期不平衡。这可以通过简单地增加队列边界来解决。
-
添加和删除队列条目的速率之间存在长期不平衡。这只能通过添加更多的使用者线程和/或删除工作线程来解决。
关键是,如果你可以让线程不需要阻塞,你就不需要担心阻塞线程的公平性。
另一个问题是公平是否真的很重要。以严格公平的方式将条目添加到队列中真的重要吗?它是否会影响应用程序的正确性?(用户是否能够判断他们的请求何时被推迟……或超过另一个用户的请求?(
(我可以想象一些要求严格公平的场景。但它们只是极少数。(
如果要求严格的公平性,那么在请求被添加到队列之前对请求的处理又如何呢。那个也需要公平吗?因为JVM和操作系统没有提供任何保证线程调度是公平的。
基本上,使请求处理完全公平是一个棘手的问题。因此,对于大多数场景来说,实现FIFO队列提交的严格公平性几乎没有意义。