Synchronized锁升级 —— MarkWord转化过程
偏向锁
创建一个对象,此时对象头中没有hashcode,该对象可以使用偏向锁,偏向锁不会考虑hashcode,而是直接将线程ID设置到MarkWord中,不需要考虑后续的替换问题。因此,一旦对象调用了Object#hashcode()
方法,偏向锁自动不可用了。
轻量级锁
如果对象有hashcode + 分代年龄 +
偏向锁标志位(30位),在轻量级锁状态下,这30位信息会被复制到轻量级锁持有者线程的栈帧中的LockRecord中,此时,对象的MarkWord中存放的是指向轻量级锁持有者线程的栈帧中的LockRecord的指针(Displace MarkWord
过程)。如果一直存在轻量级锁竞争,在未发生锁膨胀的前提下,会一直保持轻量级锁,线程A释放锁的时候,会将MarkWord替换回对象的MarkWord中,线程B再重新进行Displace MarkWord
。
轻量级锁膨胀
一旦发生了轻量级锁膨胀为重量级锁(前提:线程A持有轻量级锁,线程B争抢该锁),线程B将MarkWord中线程A的指针替换成一个临时的重量级锁指针(目的是让线程A在使用CAS设置对象的MarkWord的操作失败),线程A替换MarkWord失败后,会触发以下步骤:
- 初始化Monitor对象
- 将锁状态设置为膨胀中
- 将替换失败的MarkWord设置到ObjectMonitor的header属性中
- 修改MarkWord的锁标志位为10,将MarkWord中的30位(hashcode + 分代年龄 + 偏向锁标志位)设置为指向第一步中创建的Monitor对象的指针
- 唤醒争抢锁的线程
- 之后该对象只能作为重量级锁
整个过程MarkWord没有丢失
资料:https://www.bilibili.com/video/BV1Pa4y1S7qF/ 强推 河北王校长