Skip to content
进阶

一句话答案

阻塞队列基于 ReentrantLock + 两个 Condition:put 时队满阻塞(notFull.await),take 时队空阻塞(notEmpty.await)。

核心要点

作用: 为每个线程提供独立的变量副本,线程间互不影响(线程隔离)。

典型应用:

  • 存储当前登录用户信息(UserContextHolder),避免在方法间传参
  • 数据库连接(保证同一线程的事务用同一个 Connection)
  • SimpleDateFormat(非线程安全,每个线程一个副本)

实现原理:

每个 Thread 对象内部有一个 ThreadLocalMap:
Thread.threadLocals = ThreadLocalMap(由 ThreadLocal 维护)

ThreadLocalMap 是一个 Entry[] 数组(开放地址法处理哈希冲突)
  Entry 的 key = ThreadLocal 对象(弱引用)
  Entry 的 value = 对应线程的变量值(强引用)

ThreadLocal.set(value):
  获取当前线程 → 获取/创建 ThreadLocalMap → 以 this(ThreadLocal) 为 key,存入 value

ThreadLocal.get():
  获取当前线程 → 获取 ThreadLocalMap → 以 this(ThreadLocal) 为 key,找到 value 返回

数据结构示意:

Thread A:
  threadLocals = {
    ThreadLocal1 → "UserA",
    ThreadLocal2 → Connection_A
  }

Thread B:
  threadLocals = {
    ThreadLocal1 → "UserB",   ← 与 Thread A 完全独立
    ThreadLocal2 → Connection_B
  }
追问与易错

追问方向:

  • ArrayBQ 和 LinkedBQ 用哪个?
  • SynchronousQueue 有什么特殊?
  • DelayQueue 怎么实现延迟?

易错点:

  • ❌ BlockingQueue 都是有界的——LinkedBQ 默认无界
  • ❌ 用 add/remove 而不是 put/take

💡 记忆锚点

阻塞队列像一条传送带:一把锁锁住传送带,两个铃铛分别叫"没满"和"没空"。放货的人发现传送带满了就等"没满"铃响,取货的人发现传送带空了就等"没空"铃响——一个 Lock 加两个 Condition 就是全部。