轻量级锁
引入轻量级锁的目的是为了避免在没有多线程竞争的情况下,由于互斥信号量造成的不必要性能浪费。
基础知识
轻量级锁加锁解锁总共需要两次CAS。其操作的模板是instance对象头中的Mark Word。若对对象头不是很了解的话,可以先阅读这篇文章。Java对象内存布局之谜
先决条件
- 多个线程交替获取资源,不存在同时竞争的情况。则可以使用轻量级锁。
执行过程
获取锁
- 判断instance是否被锁,即mark word 锁标志位是否为01。若是00表示instance已经被锁,需要进行锁膨胀。
- 若没有被锁,则在当前线程的栈帧上分配一块空间名为Lock Record。若被锁,则要判断instance的锁是否被当前线程持有(重入锁)。
- 将instance的mark word 拷贝到Lock Record中,名为 Displaced Mark Word。
- 进行CAS操作将mark word 更新为指向Lock Record的指针,并且将锁状态更改为 00。若执行成功则锁获取成功,若执行失败,则进行锁膨胀。
释放锁
- 取出Lock Record中的 Displaced Mark Word。
- 进行CAS将DMW赋值给instance的mark word。若赋值成功,则解锁成功,否则解锁失败,进行锁膨胀。
锁膨胀流程
锁膨胀过程其实就是重量级锁的加锁过程。Hotspot分了以下几种不同的情况去执行锁膨胀。
- Inflated 已经膨胀完成,直接返回锁
- Stack-locked 之前被轻量级锁锁定,则需要进行膨胀
- INFLATING 其他线程正在进行锁膨胀过程,则自旋等待
- Neutral 直接进行锁膨胀
- BIASED 偏向状态,不应该执行重量级锁膨胀逻辑,直接error