我想我会重新构思我的问题
您应该在哪里使用BlockingQueue实现而不是简单队列实现?
到
BlockingQueue优于队列实现的优点/缺点是什么,考虑到诸如速度,并发性或其他性质等方面的变化,例如:访问最后一个元素的时间。
我使用过这两种队列。我知道Blocking Queue通常用于并发应用程序。我正在编写简单的ByteBuffer池,我需要一个ByteBuffer对象的占位符。我需要最快,线程安全的队列实现。甚至像ArrayList这样的List实现也具有元素的持续访问时间。
任何人都可以讨论BlockingQueue与Queue vs List实现的优缺点吗?
目前我使用ArrayList来保存这些ByteBuffer对象。
我应该使用哪种数据结构来保存这些对象?
答案 0 :(得分:31)
如果您想要限制某种请求,有限容量BlockingQueue
也会有所帮助。通过无限制的队列,生产者可以远远领先于消费者。这些任务最终会被执行(除非它们有很多导致OutOfMemoryError
),但是生产者可能早已放弃,因此浪费了精力。
在这样的情况下,最好向潜在的生产者发出队列已满的信号,并快速放弃失败。例如,生产者可能是一个Web请求,用户不想等待太长时间,即使它在等待时不会占用很多CPU周期,也会占用有限的资源,如套接字和一些内存。放弃将使排队的任务更有机会及时完成。
关于修正后的问题,我将其解释为“在游泳池中保存物品有什么好处?”
无界LinkedBlockingQueue
是许多游泳池的不错选择。但是,根据您的池管理策略,ConcurrentLinkedQueue
也可能有效。
在池化应用程序中,阻止“put”是不合适的。控制队列的最大大小是池管理器的工作 - 它决定何时创建或销毁池的资源。池的客户端从池中借用和返回资源。添加新对象或将先前借用的对象返回池应该是快速,无阻塞的操作。因此,有界容量队列不是池的好选择。
另一方面,从池中检索对象时,大多数应用程序都希望等到资源可用。至少暂时阻止的“接受”操作比“忙等待”更有效 - 重复轮询直到资源可用。在这种情况下,LinkedBlockingQueue
是一个不错的选择。借款人可以使用take
无限期阻止,或使用poll
限制其愿意阻止的时间。
一种不常见的情况,当客户端根本不愿意阻塞时,但如果池为空,则能够为自己创建资源。在这种情况下,ConcurrentLinkedQueue
是一个不错的选择。这是一个灰色区域,尽可能多地共享资源(例如,内存),但速度更为重要。在更糟糕的情况下,这会退化为具有自己的资源实例的每个线程;那么不打算尝试在线程之间共享会更有效率。
这两个集合在并发应用程序中提供了良好的性能和易用性。对于非并发应用程序,ArrayList
很难被击败。即使对于动态增长的集合,LinkedList
的每元素开销也允许带有一些空插槽的ArrayList
在内存方面保持竞争力。
答案 1 :(得分:3)
您会在多线程情况下看到BlockingQueue
。例如,如果要使用构造函数创建一个参数,则需要传入BlockingQueue
作为参数来创建ThreadPoolExecutor
。根据您传入的队列类型,执行程序可能采取不同的行动。
答案 2 :(得分:1)
这是一个Queue
实现,另外支持
在检索元素时等待队列变为非空,
和
存储时等待队列中的空间可用 元件。
如果您需要上述功能,则Queue
实施后会使用Blocking Queue
答案 3 :(得分:0)
BlockingQueue
对于序列化彼此依赖的并行操作也很有用。
为了带来一个具体的(虽然有点武断)示例,here是对callInPatient()
需要与registerPatientToAppointment()
并行启动的实时患者队列Web应用程序的并行测试,但需要等到registerPatientToAppointment()
完成才能执行callPatientInAtDoctorsOffice()
:
public class ClinicPatientQueueAppTest extends ParallelTest {
private static final BlockingQueue WAIT_FOR_REGISTRATION_QUEUE = new ArrayBlockingQueue(2);
@Test
public void callInPatient() {
loginToDoctorsOffice("user", "password");
waitUntilRegistrationCompleted(); // <--
callPatientInAtDoctorsOffice();
}
@Test
public void registerPatientToAppointment() {
registerPatientAtRegistrationKiosk("Patient Peter");
notifyRegistrationCompleted(); // <--
}
private void waitUntilRegistrationCompleted() {
WAIT_FOR_REGISTRATION_QUEUE.take();
}
private void notifyRegistrationCompleted() {
WAIT_FOR_REGISTRATION_QUEUE.put(this);
}
}