1. 概述
Java 的BlockingQueue
接口表示一个线程安全的队列。 当队列满时,尝试向队列中添加元素的线程会被阻塞;当队列为空时,尝试从中取元素的线程也会被阻塞。
BlockingQueue
有多种实现,如ArrayBlockingQueue
、LinkedBlockingQueue
、SynchronousQueue
和PriorityBlockingQueue
。
在这个教程中,我们将比较ArrayBlockingQueue
和LinkedBlockingQueue
的区别。
2. ArrayBlockingQueue
ArrayBlockingQueue
是一个有界队列,内部使用数组。创建实例时可以指定数组的大小。
下面的代码片段展示了如何创建ArrayBlockingQueue
实例,我们指定了内部数组的大小为10:
int INIT_CAPACITY = 10;
BlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(INIT_CAPACITY, true);
如果在队列已满时插入元素,或者初始容量小于1,add
操作会抛出IllegalStateException
。此外,如果我们设置的初始大小小于1,会得到IllegalArgumentException
。
第二个参数代表公平策略。 可选地设置公平策略可以维护阻塞生产者和消费者线程的顺序。这允许线程按照FIFO(先进先出)顺序访问队列,从而避免线程饥饿。
3. LinkedBlockingQueue
LinkedBlockingQueue
是BlockingQueue
的一种可选有界实现,它基于链表节点。
创建实例时也可以指定容量。如果不指定,则默认容量为Integer.MAX_VALUE
。
当插入元素时,会动态创建链表节点。
让我们看看如何创建LinkedBlockingQueue
:
BlockingQueue<String> linkedBlockingQueue = new LinkedBlockingQueue<>();
4. ArrayBlockingQueue
与LinkedBlockingQueue
比较
尽管ArrayBlockingQueue
和LinkedBlockingQueue
都是BlockingQueue
的实现,并且都以FIFO方式存储元素,但它们之间存在一些差异。现在我们来看看这些区别:
特性
ArrayBlockingQueue
LinkedBlockingQueue
实现
它基于数组
它使用链表节点
队列大小
它是有界的队列,因此创建时必须指定初始容量。
不需要指定大小。
公平策略
可以在其中设置公平策略
这个没有公平策略选项
锁数量
它使用一个ReentrantLock
,put和take操作共用同一个锁。
它为读写操作使用单独的ReentrantLock
,这减少了生产者和消费者线程之间的竞争。
内存空间
由于必须指定初始容量,可能会分配超过所需的内存。
通常不预分配节点,所以其内存占用与大小匹配
5. 总结
在这篇文章中,我们了解了ArrayBlockingQueue
和LinkedBlockingQueue
之间的区别。ArrayBlockingQueue
基于数组,而LinkedBlockingQueue
基于链表节点。我们还讨论了ArrayBlockingQueue
中存在的公平策略额外功能,以及两个队列的锁定机制和内存占用。
如往常一样,示例代码可在GitHub上找到。