外观
一句话答案
阻塞队列基于 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 就是全部。