EntryList 是 ObjectMonitor 中存放竞争锁失败、处于 BLOCKED 状态的线程队列,采用双向链表实现;线程在此排队等待锁释放后被唤醒竞争,与存放 wait() 线程的 WaitSet 严格分离。

synchronized 在 Java 中的底层实现,依赖于 JVM 的 ObjectMonitor 结构,而 EntryList 是其中关键的一环——它不是“等待队列”的全部,而是专门用于管理**尚未获得锁、正在竞争锁的线程队列**。
EntryList 是什么?
当一个线程尝试进入被 synchronized 修饰的代码块或方法时,若此时锁(即 ObjectMonitor)已被其他线程持有,该线程不会立即阻塞在操作系统层面,而是先被放入 ObjectMonitor 的 EntryList 中。这是一个由 JVM 维护的、基于双向链表(或类似结构)实现的等待队列,存放所有“已排队、待抢锁”的线程。
注意:EntryList 中的线程处于 BLOCKED 状态(JVM 线程状态),但尚未调用操作系统的挂起(如 pthread_cond_wait),属于 JVM 层的轻量级排队。
EntryList 和 WaitSet 的区别要拎清
- EntryList:存的是“想进临界区但进不去”的线程(因锁被占),等锁释放后,JVM 会从中挑选一个唤醒去竞争锁;
-
WaitSet:存的是“已经进过临界区、但主动调用了
wait()” 的线程,它们放弃锁并等待被notify()/notifyAll()唤醒,唤醒后不直接抢锁,而是重新进入 EntryList 排队。
简单说:EntryList 是“门外等开门”,WaitSet 是“进去后自己退到走廊等通知”,二者逻辑分离、互不混淆。
立即学习“Java免费学习笔记(深入)”;
EntryList 怎么被使用的?
锁释放(monitorexit)时,JVM 会做几件事:
- 清空持有锁的线程标记;
- 若 EntryList 非空,从中取出一个线程(通常是 FIFO,但不保证绝对公平);
- 将该线程状态设为 RUNNABLE,并尝试让它竞争锁(可能再次失败,再回 EntryList);
- 如果 EntryList 为空,且存在 WaitSet 中的线程,
notifyAll()会把 WaitSet 全部移到 EntryList 尾部(注意:是移动,不是唤醒执行)。
所以,“唤醒 wait 线程”不等于“立刻执行”,只是给了它一次重新排队抢锁的机会。
为什么看不到 EntryList 的直接操作?
因为 EntryList 完全由 JVM 内部管理,Java 层面没有 API 可以查看或干预它。你无法通过 ThreadMXBean 或 jstack 直接看到 “EntryList 中有哪些线程”。jstack 输出中的 java.lang.Thread.State: BLOCKED (on object monitor),背后大概率就是该线程正躺在某个 ObjectMonitor 的 EntryList 里。
验证小技巧:写一个锁竞争激烈的测试(多个线程反复争同一把锁),用 jstack 抓堆栈,常能看到一堆线程卡在 synchronized 方法入口处,状态为 BLOCKED —— 这就是 EntryList 在起作用的间接证据。
理解 EntryList 的关键,在于跳出“锁=互斥开关”的简单认知,把它看作 JVM 为公平调度、减少系统调用开销而设计的一层协作队列。它让锁竞争更可控,也为偏向锁、轻量级锁等优化提供了基础。


















