Java LinkedBlockingQueue面试题
1. 什么是LinkedBlockingQueue?
LinkedBlockingQueue是一个基于链表结构的阻塞队列,使用ReentrantLock和Condition来实现线程同步,是一个FIFO(先进先出)队列。
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
2. LinkedBlockingQueue的主要特点是什么?
- 线程安全:支持多个线程同时访问。
- 阻塞操作:当队列为空时,从队列中取数据的操作会被阻塞;当队列满时,向队列中添加数据的操作会被阻塞。
- 容量限制:可以设置容量上限,也可以设置为无界。
LinkedBlockingQueue<Integer> queueWithCapacity = new LinkedBlockingQueue<>(10); // 有界队列
LinkedBlockingQueue<Integer> queueWithoutCapacity = new LinkedBlockingQueue<>(); // 无界队列
3. LinkedBlockingQueue如何添加元素?
使用put
方法添加元素,如果队列满了,会阻塞直到队列中有空间。
boolean added = queue.offer(1); // 添加元素,如果队列满了会返回false
4. LinkedBlockingQueue如何移除元素?
使用take
方法移除元素,如果队列为空,会阻塞直到队列中有元素。
Integer element = queue.take(); // 移除并返回队列头部元素,如果队列为空会阻塞
5. LinkedBlockingQueue的迭代器是否是弱一致性的?
是的,LinkedBlockingQueue的迭代器是弱一致性的,它只能反映结构性修改,不能反映由并发一致性条件所发生的迭代器创建后的变化。
Iterator<Integer> iterator = queue.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
}
6. LinkedBlockingQueue的poll和peek方法有什么区别?
poll
:移除并返回队列头部的元素,如果队列为空则返回null
。peek
:返回队列头部的元素但不移除,如果队列为空则返回null
。
Integer polledElement = queue.poll(); // 移除并返回队列头部元素
Integer peekedElement = queue.peek(); // 返回队列头部元素但不移除
7. LinkedBlockingQueue是否允许null元素?
是的,LinkedBlockingQueue允许null元素。
queue.put(null); // 允许添加null元素
8. LinkedBlockingQueue的容量有什么限制?
如果构造时指定了容量,则队列的最大容量为该值;如果未指定容量,则队列为无界队列。
9. LinkedBlockingQueue如何实现线程安全的队列操作?
通过内置锁和条件变量来实现线程安全的队列操作。
10. LinkedBlockingQueue的size方法有什么特点?
返回队列中的元素数量,但是一个近似值,因为队列是并发访问的。
int size = queue.size(); // 返回队列大小
11. LinkedBlockingQueue的isEmpty方法是如何工作的?
返回队列是否为空。
boolean empty = queue.isEmpty(); // 检查队列是否为空
12. LinkedBlockingQueue如何实现生产者-消费者模型?
生产者使用put
方法添加元素,消费者使用take
方法移除元素。
// 生产者
new Thread(() -> {
try {
queue.put(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 消费者
new Thread(() -> {
try {
Integer element = queue.take();
System.out.println(element);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
13. LinkedBlockingQueue的剩余容量是多少?
使用remainingCapacity
方法返回队列的剩余容量。
int remainingCapacity = queue.remainingCapacity(); // 返回队列的剩余容量
14. LinkedBlockingQueue是否支持公平性?
构造时可以指定是否是公平性队列。公平性队列按照线程等待时间的长短来分配队列资源。
LinkedBlockingQueue<Integer> fairQueue = new LinkedBlockingQueue<>(10, true); // 公平性队列
15. LinkedBlockingQueue的clear方法有什么作用?
清除队列中的所有元素。
queue.clear(); // 清除队列中的所有元素
16. LinkedBlockingQueue的drainTo方法有什么作用?
将队列中的所有元素转移到另一个集合中。
List<Integer> list = new ArrayList<>();
int drainedCount = queue.drainTo(list); // 将队列中的所有元素转移到list中
17. LinkedBlockingQueue的put和offer有什么区别?
put
:如果队列满了,会阻塞直到队列中有空间。offer
:如果队列满了,会返回false
而不阻塞。
try {
queue.put(1); // 队列满了会阻塞
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
boolean offered = queue.offer(1); // 队列满了会返回false
18. LinkedBlockingQueue的take和poll有什么区别?
take
:如果队列为空,会阻塞直到队列中有元素。poll
:如果队列为空,会返回null
而不阻塞。
try {
Integer element = queue.take(); // 队列为空会阻塞
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Integer polledElement = queue.poll(); // 队列为空会返回null
19. LinkedBlockingQueue如何实现FIFO?
通过链表结构实现FIFO,队列头部是最先添加的元素,队列尾部是最后添加的元素。
20. LinkedBlockingQueue的数组复制开销大吗?
在高并发写操作时,数组复制的开销可能较大,因为每次修改操作都需要复制整个数组。