在 Java 中,synchronized 关键字用于实现线程之间的互斥访问,保证了共享资源的线程安全。为了提高性能,JVM 在对 synchronized 进行优化时,使用了锁升级的机制,即从无锁状态到偏向锁状态(Bias Locking)、再到轻量级锁状态(Lightweight Locking),最后升级为重量级锁状态(Heavyweight Locking)。
锁升级的原理如下:
1. 无锁状态(Unlocked):当一个线程访问一个同步块时,如果没有竞争,那么该线程可以直接进入临界区,无需等待或申请锁。此时,该对象为无锁状态。
2. 偏向锁状态(Biased Locking):当一个线程进入临界区并获取锁后,该对象会被标记为偏向锁状态。此时,如果其他线程再次进入这个临界区,JVM 会检查该对象是否被偏向锁所拥有。如果是,则直接进入临界区,无需再次竞争锁。这样可以避免大多数情况下的不必要竞争,提高性能。
3. 轻量级锁状态(Lightweight Locking):当两个线程同时进入临界区时,会发生锁的竞争。JVM 会将对象的标记从偏向锁升级为轻量级锁。在轻量级锁状态下,JVM 使用 CAS(Compare And Swap)操作来尝试获取锁,如果成功则进入临界区,如果失败则进入重量级锁状态。
4. 重量级锁状态(Heavyweight Locking):如果在轻量级锁状态下 CAS 操作获取锁失败,JVM 会将对象标记为重量级锁。在重量级锁状态下,线程会进入阻塞状态,由操作系统负责线程的阻塞和唤醒,这种情况下的锁升级会带来较大的性能开销。
锁升级的过程是根据竞争情况动态进行的,JVM 会根据运行时的具体情况和性能数据进行优化决策。锁的升级过程是自动的,开发者无需手动干预。通过锁升级机制,JVM 尽可能地减少了不必要的锁竞争,提高了多线程程序的性能。