当一个 Java 对象的锁通过 synchronized
升级到重量级锁之后,即使所有线程都释放了这个锁,该对象的锁仍然保持为重量级锁的状态。
这是因为锁膨胀(Lock Escalation)在 JVM 中是单向的,一旦从偏向锁或轻量级锁升级到了重量级锁,就不会自动降级回之前的锁状态。
锁的升级路径
- 偏向锁:JVM 默认开启的锁优化机制,旨在消除无竞争同步的开销。当一个线程第一次获取锁时,JVM会将对象头的Mark Word设置为偏向模式,并记录下持有锁的线程ID。
如果接下来没有其他线程尝试获取该锁,则无需进行任何同步操作。 - 轻量级锁:当有多个线程尝试获取同一个锁但不存在实际竞争时(即这些尝试不是同时发生的),JVM 会使用CAS操作来尝试原子地更新对象头中的指针指向当前线程的栈帧中创建的锁记录。
这允许锁可以在不涉及操作系统层面的情况下被快速获取和释放。 - 重量级锁:如果存在真正的锁竞争(即两个以上的线程几乎同时尝试获取同一把锁),那么锁会被升级为重量级锁。
此时,JVM 将依赖于操作系统的互斥量(mutex)实现来管理锁,这涉及到线程挂起和恢复等高成本的操作。
关键点
- 不可逆性:一旦锁升级成为重量级锁,即使后续所有的线程都已经释放了该锁,它也不会自动降级回到偏向锁或者轻量级锁的形式。
这是因为重量级锁涉及到的操作系统级别的资源管理,降级过程复杂且没有必要。 - 性能影响:虽然重量级锁解决了多线程并发访问共享资源的问题,但它相比偏向锁和轻量级锁来说,带来了更高的开销,包括上下文切换、线程调度等。
因此,在设计并发程序时,应尽量减少不必要的锁竞争,以避免锁升级带来的性能损耗。
综上所述,即使所有线程都释放了锁,对象上的锁依然保持重量级锁的状态,直到垃圾回收器决定清理该对象或程序结束为止。
这种设计是为了简化锁管理逻辑并提高效率,尽管它可能导致一些性能上的损失。
THE END