BLOCKED状态是线程因抢锁失败被放入monitor的Entry List等待队列,仅等锁释放后重试;WAITING则是进入同步块后调用wait()释放锁并等待notify()唤醒,二者本质不同。

线程进入 BLOCKED 状态,不是“滑入”,也不是“宿主锁池”这种非标准说法——而是**因尝试进入 synchronized 代码块/方法时,发现目标对象的监视器锁(monitor)正被其他线程持有,于是被 JVM 暂时挂起,放入该锁关联的“入口等待队列”(Entry List)中,状态变为 BLOCKED**。
BLOCKED 的本质是“卡在门口,还没进门”
它不涉及任何主动让出、不释放已有资源、也不等待通知:
- 线程甚至没执行到 synchronized 块内部,连锁都没拿到,更谈不上释放或等待唤醒
- 它只是在“抢锁失败”那一刻,被 JVM 纳入对应 monitor 的竞争队列,暂停调度
- 一旦持有锁的线程退出同步块(正常结束或抛异常),JVM 就自动从这个队列里挑一个线程,让它重新参与锁竞争——成功则变 RUNNABLE,失败则继续 BLOCKED
和 WAITING 的关键区别就在这里
WAITING 是“进门后主动坐下等通知”;BLOCKED 是“还在门外排队等开门”:
- BLOCKED 等的是“锁空出来”:无需其他线程干预,只要锁一释放,它就有机会冲进去
-
WAITING 等的是“别人来喊你”:比如调用了
obj.wait(),必须靠obj.notify()才能动;而且 wait 会立刻释放锁,这和 BLOCKED 完全无关 - 堆栈里看到
waiting to lock 0x...→ 典型 BLOCKED;看到waiting on 0x...或parking to wait for...→ 典型 WAITING
实际代码中一眼识别 BLOCKED
看线程是否在 刚碰到 synchronized 就停住:
- ✅ t2 启动后立即执行
synchronized(lock) { ... },但 lock 正被 t1 占着 → t2 进入 BLOCKED - ❌ t1 在 synchronized 块内调用
lock.wait()→ t1 释放锁,状态变成 WAITING,不是 BLOCKED - ⚠️ t1 wait 后被 notify,但此时 lock 又被别的线程占着 → t1 被唤醒后抢锁失败,这时才进 BLOCKED
没有“宿主锁池”,只有规范的 monitor 队列
JVM 规范中,每个对象监视器维护两个逻辑队列:
- Entry List(入口队列):存放所有 BLOCKED 线程,等锁释放后参与竞争
-
Wait Set(等待队列):存放所有因
wait()进入 WAITING 的线程,需notify()唤醒
所谓“锁池”是早期非正式说法,容易混淆。准确理解应聚焦于:BLOCKED = 竞争锁失败 + 在 Entry List 中排队 + 等锁释放后重试。

















