奇安信一面:咱们聊一聊什么叫做阻塞队列的有界和无界?
面试官:什么叫做阻塞队列的有界和无界?能否结合源码分析一下?并站在架构设计的角度谈谈它们的作用。
我:好的,这个问题很有意思,我来为您详细解释一下。
1. 阻塞队列的有界和无界
(1) 有界阻塞队列
- 定义:有界阻塞队列有一个固定的容量上限。例如,你可以定义一个容量为10的队列,一旦队列满了,再往队列中添加元素就会被阻塞,直到队列中有空闲空间。
- 源码示例:在Java中,ArrayBlockingQueue是一个典型的有界阻塞队列。它的构造函数中需要指定容量大小,当队列满时,put方法会阻塞,直到有空间可用。
- 架构设计的作用:
- 防止资源耗尽:有界队列可以限制队列的最大容量,从而防止系统资源被无限制地占用。
- 控制生产者速度:当队列满了,生产者线程会被阻塞,这可以间接控制生产者的速度,避免生产者过快地生成任务。
(2) 无界阻塞队列
- 定义:无界阻塞队列的容量理论上是无限的,生产者可以不断地往队列中添加元素,而不用担心队列满。
- 源码示例:LinkedBlockingQueue在不指定容量时,默认是无界的(实际上是受限于内存大小)。生产者线程不会因为队列满而被阻塞。
- 架构设计的作用:
- 简单易用:生产者不需要关心队列是否满了,只需不断地添加任务即可。
- 性能问题:无界队列可能会导致系统资源被无限制地占用,比如内存溢出。
2. 架构设计中的选择
(1) 有界队列的优势
- 资源控制:有界队列可以有效防止系统资源被过度占用,避免内存泄漏。
- 系统稳定性:通过限制队列大小,可以避免生产者过快地生成任务,从而保证系统的稳定性和可靠性。
(2) 无界队列的劣势
- 资源耗尽风险:无界队列可能会导致系统资源被无限制地占用,甚至引发内存溢出。
- 缺乏控制:生产者可能会过度生成任务,导致系统负载过高。
3. 结合源码分析
(1) ArrayBlockingQueue(有界)
java复制
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity]; // 定义固定大小的数组
this.capacity = capacity;
this.lock = new ReentrantLock(fair);
this.notEmpty = lock.newCondition();
this.notFull = lock.newCondition();
}
- 核心逻辑:当队列满时,put方法会阻塞,直到有空间可用。
- 架构设计:有界队列通过限制容量,避免了资源耗尽的问题。
(2) LinkedBlockingQueue(无界)
java复制
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE); // 默认容量为Integer.MAX_VALUE,接近无界
}
- 核心逻辑:生产者线程不会因为队列满而被阻塞。
- 架构设计:无界队列简化了设计,但需要小心资源耗尽的问题。
4. 架构设计建议
在实际架构设计中,建议优先使用有界阻塞队列,因为它可以有效防止资源耗尽和生产者过快生成任务,从而保证系统的稳定性和可靠性。当然,具体选择还需要根据业务需求和资源情况进行权衡。
面试官:好的,谢谢你的回答!