偏向锁是JVM为单线程反复加锁场景设计的免检机制,通过在对象头记录线程ID实现零成本重入;一旦有竞争即撤销并升级为轻量级锁。

偏向锁:单线程场景下的“免检通道”
偏向锁是 JVM 锁优化的起点,专为“一个对象长期被同一个线程反复加锁”的场景设计。它不追求多线程公平,而是信任——一旦线程 A 首次获得某对象的锁,JVM 就在对象头(Mark Word)中记录 A 的线程 ID,并将锁状态设为“可偏向”(标志位 01,偏向标识为 1)。后续 A 再次进入 synchronized 块时,只需比对线程 ID 是否一致,无需 CAS、无需同步,直接执行。
这种机制把锁获取开销压到最低:仅初始化一次 CAS,之后零成本。但它的脆弱点也很明确——只要出现第二个线程尝试竞争,偏向锁就会被撤销(需等待全局安全点),并升级为轻量级锁。JVM 默认开启偏向锁(-XX:+UseBiasedLocking),若应用明显存在多线程争用,可关闭以避免撤销开销。
轻量级锁:无阻塞的“快速轮询”机制
当偏向锁被打破,或对象从未被偏向,线程进入同步块时会尝试轻量级锁。此时 JVM 在当前线程栈帧中创建一个 Lock Record,复制对象原 Mark Word(Displaced Mark Word),再用 CAS 将对象头更新为指向该记录的指针(锁标志位变为 00)。
关键在于:轻量级锁本身不阻塞线程。如果持有锁的线程很快释放(比如临界区只有几行赋值),等待线程可通过自旋(spin)反复检查锁是否释放——这就是轻量级锁与自旋锁的天然耦合。它避免了用户态→内核态切换,但代价是占用 CPU 时间。一旦自旋失败次数超过阈值(默认 10 次),或 JVM 判断自旋收益低(如临界区耗时变长),就会触发锁膨胀。
自适应自旋锁:动态调优的忙等策略
自旋不是固定次数的硬编码,而是 JVM 的智能反馈机制。例如:线程第一次自旋 10 次成功抢到锁,下次对该锁的自旋上限可能提升至 20 次;反之,若连续几次都未在自旋中获胜,JVM 会逐步降低自旋次数,甚至跳过自旋直接升级。
这种“自适应”依赖于历史行为统计,目标很务实:在锁持有时间短、竞争不激烈时,用 CPU 换时间;在锁持有时间长、竞争频繁时,及时止损,避免空转浪费。它不改变锁状态,而是作为轻量级锁内部的获取辅助策略,存在于整个轻量级锁生命周期中。
重量级锁:系统级互斥的最终防线
当轻量级锁自旋失败,或 JVM 检测到锁竞争加剧(如多个线程反复自旋失败),对象锁就会膨胀为重量级锁。此时 Mark Word 被替换为指向操作系统 Monitor 的指针(锁标志位 10),所有未抢到锁的线程将被挂起,进入阻塞队列(ObjectMonitor 的 _WaitSet 或 _EntryList)。
重量级锁意味着真正的线程调度介入:用户态切换至内核态、线程上下文保存/恢复、CPU 时间片让渡。性能开销显著上升,但换来的是强一致性与公平性保障。值得注意的是,锁升级是单向的——从无锁 → 偏向 → 轻量 → 重量,不会降级。这是为了规避降级带来的复杂性与额外开销,符合“宁可保守,不可误判”的优化哲学。

















