面试知识库
进阶

BlockingQueue实现原理#

一句话答案#

BlockingQueue 通过 ReentrantLock + Condition(notEmpty/notFull)实现线程安全的阻塞入队出队:队满时 put 阻塞等待 notFull,队空时 take 阻塞等待 notEmpty。

核心要点

核心操作#

操作抛异常返回特殊值阻塞超时
入队add(e)offer(e)put(e)offer(e, timeout)
出队remove()poll()take()poll(timeout)

ArrayBlockingQueue 原理#

用 while 不用 if——防止虚假唤醒。

Array vs Linked#

维度ArrayBlockingQueueLinkedBlockingQueue
一把锁(读写互斥)两把锁(putLock + takeLock)
并发较低较高(读写可并行)
内存预分配,无 GC每次 put 创建 Node
默认容量必须指定Integer.MAX_VALUE(危险!)

在线程池中的应用#

队列特点适用
ArrayBlockingQueue有界严格限制队列大小
LinkedBlockingQueue可选有界通用(必须设容量)
SynchronousQueue无容量,直接传递高吞吐
PriorityBlockingQueue按优先级优先级调度

陷阱: LinkedBlockingQueue 不设容量 → 默认 MAX_VALUE → OOM。Executors.newFixedThreadPool 就用了无界队列。

面试回答(2分钟版)

BlockingQueue 是 Java 并发中实现生产者-消费者模式的核心组件,底层通过 ReentrantLock 加两个 Condition 来保证线程安全的阻塞入队出队。具体来说,队列满时 put 操作会阻塞在 notFull 条件上等待,队列空时 take 操作会阻塞在 notEmpty 条件上等待,入队成功后唤醒 notEmpty,出队成功后唤醒 notFull,形成完整的协作机制。等待条件用 while 而不是 if 来防止虚假唤醒。常用实现中,ArrayBlockingQueue 用一把锁读写互斥,LinkedBlockingQueue 用两把锁(putLock 和 takeLock)使读写可并行,并发性能更高。实际使用中有一个非常重要的陷阱:LinkedBlockingQueue 默认容量是 Integer.MAX_VALUE,相当于无界队列,生产中必须显式设置容量,否则队列无限增长会导致 OOM。

追问与易错

追问方向:

  • “为什么用 while 不用 if?”→ 防止虚假唤醒
  • “LinkedBlockingQueue 为什么用两把锁?”→ 入队操作尾部、出队操作头部,不冲突

易错点:

  • ❌ “BlockingQueue 是无锁的”——基于 ReentrantLock + Condition
  • ❌ “ArrayBlockingQueue 读写可并行”——只有一把锁,读写互斥