锁的疑问及细节
锁升级的过程
无锁状态
-> 偏向锁
JVM
默认开启偏向锁-XX:+UseBiasedLocking
JVM
启动后4s开启-XX:BiasedLockingStartupDelay=4000
,查看对象内存布局会看到101
JVM
启动过程,会有很多线程竞争,所以默认情况启动时不打开偏向锁,延迟打开。出现线程竞争锁,则偏向锁升级为轻量级锁。
-> 轻量级锁
线程在自己的线程栈桢中生成锁记录(
Lock Record
) ,用CAS
操作将对象mark word
设置为指向自己这个线程的LR的指针,设置成功者得到锁。
如果
CAS
次数超过阀值、自旋线程超过CPU
核数的一半则升级为重量级锁
-> 重量级锁
计算过对象的hashCode,将无法进入偏向锁模式
当对象进入偏向状态的时候,Mark Word
大部分(23个比特)都用于存储持有锁的线程ID,
这部分空间占用了原有存储对象哈希码的位置,那原来对象的哈希码怎么办?
对象的一致性哈希码(Identity Hash Code
),这个值需要保证不变的,
它通过在对象头中存储计算结果来保证第一次计算之后,再次调用该方法取到的哈希值
永远不会变化。因此当一个对象计算过一次哈希码后,它就再无法进入偏向锁状态了;
当一个对象处于偏向锁状态又收到需要计算其一致性哈希码请求时,偏向状态会立即撤销,
并且锁会膨胀为重量级锁。
轻量级锁状态下的对象的
hashCode
暂存在线程栈的中Lock Record
中,重量级锁状态下的对象的
hashCode
暂存在ObjectMonitor
中。