持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第33天,点击查看活动详情
1.偏向锁:
每当遇到一个全局安全点时(这里的意思是说批量重偏向没有完全替代了全局安全点,全局安全点是一直存在的),比如要对class C 进行批量再偏向,则首先对 class C中保存的epoch进行增加操作,得到一个新的epoch_new
然后扫描所有持有 class C 实例的线程栈,根据线程栈的信息判断出该线程是否锁定了该对象,仅将epoch_new的值赋给被锁定的对象中,也就是现在偏向锁还在被使用的对象才会被赋值epoch_new。
当线程访问同步块并获取锁时处理流程如下:
- 检查
mark word
的线程 id
。 - 如果为空则设置 CAS 替换当前线程 id。如果替换成功则获取锁成功,如果失败则撤销偏向锁。
- 如果不为空则检查
线程 id
为是否为本线程。如果是则获取锁成功,如果失败则撤销偏向锁。
持有偏向锁的线程以后每次进入这个锁相关的同步块时,只需比对一下 mark word 的线程 id 是否为本线程,如果是则获取锁成功。
如果发生线程竞争发生 2、3 步失败的情况则需要撤销偏向锁。
解锁:
- 偏向锁的撤销动作必须等待全局安全点
- 暂停拥有偏向锁的线程,判断锁对象是否处于被锁定状态
- 撤销偏向锁恢复到无锁(标志位为 01)或轻量级锁(标志位为 00)的状态
2.轻量级锁,加解锁中CAS具体分析:
轻量级锁加锁和解锁的CAS比较,比较的内容是什么?
-
加锁:
-
加锁过程中CAS操作的是mark word中的pointer
-
当前值是目前程序中mark word中的pointer的值,pointer的预期原值是null,而目的值则是指向自己的线程栈。
-
简单来说,当前值=预期值=null,修改为目的值。
也就是只有在pointer是null的时候也就是没有线程获取对象锁。才能够使CAS操作成功。
如果失败,有两种情况:
- 一种情况是该线程持有该锁,一看pointer是指向自己那无所谓,继续执行同步块,
- 另一种情况不是指向自己,那不好意思发生了竞争,反手我就膨胀成重量级锁。于是这又让后面的轻量级锁的解锁过程CAS有了用武之地。
- 解锁:
- 解锁过程操作的是整个markword,解锁过程就是将先前复制锁对象的mark word又给替换回去。
- 当前值是目前程序中的markword的值,预期值是lockrecod存的值,而目的值是把markword修改为lockrecod的值,也就是修改为预期值。
- 简单来说:当前值=预期值,修改为目的值=预期值。
3.重量级锁
加锁:
具体的之后在做详细的讲解,这种主要是搞清楚轻量级锁中CAS的具体操作。