BLOCKED是线程未获锁而被挂起,等待锁释放后重竞争;WAITING是线程已持锁并主动释放,等待显式唤醒信号后才重新争锁。

本质区别在于:BLOCKED 是线程在锁竞争中“还没进门就被拦下”,CPU 调度器直接将其挂起,不分配执行时间;WAITING 是线程“已进门、主动交出钥匙并躺下”,调度器将其移出运行队列,且不参与任何锁竞争,直到被显式唤醒。
谁在等?等什么?
BLOCKED 线程等的是“锁空出来”——它正排队等着进入 synchronized 代码块,但目标对象的 monitor 锁被别人占着。它没拿到锁,也没执行到同步块内部,连 synchronized 大括号里的第一行代码都没开始跑。
WAITING 线程等的是“别人来喊一声”——它已经成功持有了锁,执行到 obj.wait() 或 thread.join() 等调用,主动释放锁、放弃 CPU,并进入等待队列,只响应 notify/unpark/interrupt 这类信号。
AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。
CPU 调度行为完全不同
- BLOCKED 线程被 JVM 放入该锁对应的 EntrySet(锁池),不参与 CPU 时间片轮转,也不消耗 CPU;一旦锁释放,JVM 自动将其从锁池取出,置为 RUNNABLE,参与下一轮锁竞争——可能立刻又变 BLOCKED(如果锁被别人抢走)
- WAITING 线程被放入 WaitSet(等待池) 或独立等待队列(如 park 场景),完全脱离锁竞争流程;它不会因锁释放而醒来,也不会自动重试获取锁;只有收到对应唤醒信号后,才回到锁池排队,再争锁,才可能恢复执行
- sleep() 不在此列:它进入 TIMED_WAITING,既不释放锁,也不进 WaitSet,和锁池/等待池都无关
看堆栈就能快速判断
jstack 输出是最快捷的依据:
- 出现 “waiting to lock ” → 说明线程卡在 synchronized 入口外,从未拿到锁,属于 BLOCKED
- 出现 “waiting on ” 或 “parking to wait for ” → 说明线程已持锁并在内部调用了 wait()/join()/park(),主动让出并等待,属于 WAITING
一个关键连锁反应:WAITING 唤醒后可能立刻再 BLOCKED
这是最容易误解的环节:
- t1 在 synchronized(lock) 内调用
lock.wait()→ 进入 WAITING,同时释放 lock - t2 抢到 lock,执行
lock.notify()→ t1 被唤醒,但不直接执行 - t1 从 WAITING 变为 RUNNABLE 后,必须重新竞争 lock;若此时 t3 已抢先获取 lock,t1 就会再次进入 BLOCKED 状态
- 也就是说:WAITING 的结束 ≠ 执行的开始;中间还隔着一次锁争夺,可能再次卡住










