Synchronized 锁升级过程

137 阅读3分钟

Synchronized 锁升级是 JVM 为优化性能,根据竞争激烈程度将锁从低开销状态逐步升级到高开销状态的过程,核心是从偏向锁→轻量级锁→重量级锁,且升级过程不可逆。

1. 偏向锁(Biased Locking)

  • 适用场景:无竞争或只有一个线程重复获取锁的场景。

  • 核心原理:锁对象头(Mark Word)会记录当前持有锁的线程 ID,后续该线程再次获取锁时,只需判断线程 ID 是否一致,无需 CAS 操作,开销极低。

  • 升级触发:当有第二个线程尝试获取该锁时,偏向锁会被撤销,升级为轻量级锁。

  • 优点:开销极低,几乎无额外消耗。首次获取锁时仅需一次 CAS 操作,后续同一线程再次获取锁,仅需判断对象头的线程 ID 是否匹配,无需任何同步操作。

  • 缺点:存在“偏向锁撤销”开销。当有第二个线程竞争锁时,需暂停持有锁的线程,将偏向锁撤销为无锁状态或升级为轻量级锁,此过程会带来性能损耗。

2. 轻量级锁(Lightweight Locking)

  • 适用场景:多个线程交替获取锁,竞争不激烈的场景。

  • 核心原理:线程在栈帧中创建“锁记录”,并通过 CAS 操作将锁对象头的 Mark Word 替换为指向该锁记录的指针。若 CAS 成功,则线程持有锁;若失败,则表示存在竞争,锁会膨胀为重量级锁。

  • 升级触发:当 CAS 操作失败,或存在线程自旋(默认 10 次)仍未获取到锁时,轻量级锁升级为重量级锁。

  • 优点:竞争不激烈时,性能优于重量级锁。通过自旋(用户态循环等待)避免线程阻塞,减少内核态与用户态的切换开销(切换开销远大于自旋)。

  • 缺点:自旋会消耗 CPU 资源。若锁竞争激烈,线程自旋多次仍未获取锁,会导致“空耗 CPU”,最终还需升级为重量级锁,额外增加升级开销。

3. 重量级锁(Heavyweight Locking)

  • 适用场景:多个线程同时竞争锁,竞争激烈的场景。

  • 核心原理:依赖操作系统的互斥量(Mutex)实现,线程获取不到锁时会被阻塞(进入内核态),释放锁时会唤醒阻塞的线程,开销较高。

  • 特点:一旦升级为重量级锁,不会再降级为轻量级锁或偏向锁。

  • 优点:能稳定处理高竞争场景。依赖操作系统互斥量(Mutex)实现,线程获取不到锁时会被阻塞(释放 CPU),不会空耗资源。

  • 缺点:开销极高。线程阻塞/唤醒需切换至内核态,操作耗时远大于用户态操作;且唤醒线程时可能存在“惊群效应”(多个线程被同时唤醒但只有一个能获取锁),进一步增加性能损耗。