java锁升级的过程
锁升级过程是由无锁,偏向锁,轻量级锁,到重量级锁的过程。
多个线程在争抢synchronized 锁时,在某些情况下,会由无锁状态一步步升级为最终的重量级锁状态。整个升级过程大致包括如下几个步骤。
- 线程在竞争 synchronized 锁时,JVM 首先会检测锁对象的 Mark word 中偏向锁锁标记位是否为 1,锁标记位是否为 01,如果两个条件都满足,则当前锁处于可偏向的状态。
- 争抢 synchronized 锁的线程检查锁对象的 Mark Word 中存储的线程 ID 是否是自己的线程 ID ,如果是自己的线程 ID,则表示处于偏向锁状态。当前线程可以,直接进入方法或者代码块执行逻辑。
- 如果锁对象的 Mark word 中存储的不是当前线程的 ID,则当前线程会通过 CAS 自旋的方式竞争锁资源。如果成功抢占到锁,则将 Mark Word 中存储的线程 ID 修改为自己的线程 ID ,将偏向锁标记设置为 1,锁标志位设置为 01,当前锁处于偏向锁状态。
- 如果当前线程通过 CAS 自旋操作竞争锁失败,则说明此时有其他线程也在争抢锁资源。此时会撤销偏向锁,触发升级为轻量级锁的操作。
- 当前线程会根据锁对象的 Mark word 中存储的线程 ID 通知对应的线程暂停,对应的线程会将 Mark Word 的内容置空。
- 当前线程与上次获取到锁的线程都会把锁对象的 HashCode 等信息复制到自己的 Displaced Mark Word中,随后两个线程都会执行 CAS 自旋操作,尝试把锁对象的 Mark Word 中的内容修改为指向自己的 Displaced Mark Word 空间来竞争锁。
- 竞争锁成功的线程获取到锁,执行方法或代码块中的逻辑。同时,竞争锁成功的线程会将锁对象的 Mark Word 中的锁标志位设置为 00,此时进入轻量级锁状态。
- 竞争失败的线程会继续使用 CAS 自旋的方式尝试竞争锁,如果自旋成功竞争到锁,则当前锁仍然处于轻量级锁状态。
- 如果线程的 CAS 自旋操作达到一定次数仍未获取到锁,则轻量级锁会膨胀为重量级锁,此时会将镇对锁的 Mark Word 中的锁标志位设置为 10,进人重量级锁状态。
总之。偏向锁发生于同一时刻只有一个线程竞争锁的场景。如果有多个线程同时竞争锁,则偏向镇会升级为轻量级锁。如果线程的 CAS 自旋操作达到一定次数仍未竞争到锁,则轻量级锁会升级为重量级锁。