轻量级锁中CAS具体比较的是什么?

941 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第33天,点击查看活动详情

1.偏向锁:

每当遇到一个全局安全点时(这里的意思是说批量重偏向没有完全替代了全局安全点,全局安全点是一直存在的),比如要对class C 进行批量再偏向,则首先对 class C中保存的epoch进行增加操作,得到一个新的epoch_new

然后扫描所有持有 class C 实例的线程栈,根据线程栈的信息判断出该线程是否锁定了该对象,仅将epoch_new的值赋给被锁定的对象中,也就是现在偏向锁还在被使用的对象才会被赋值epoch_new。

v2-560c56b6beba02db8e1c860a5473f8f7_720w.jpg

当线程访问同步块并获取锁时处理流程如下:

  1. 检查 mark word 的线程 id 。
  2. 如果为空则设置 CAS 替换当前线程 id。如果替换成功则获取锁成功,如果失败则撤销偏向锁。
  3. 如果不为空则检查 线程 id为是否为本线程。如果是则获取锁成功,如果失败则撤销偏向锁。

持有偏向锁的线程以后每次进入这个锁相关的同步块时,只需比对一下 mark word 的线程 id 是否为本线程,如果是则获取锁成功。

如果发生线程竞争发生 2、3 步失败的情况则需要撤销偏向锁。

解锁:

  1. 偏向锁的撤销动作必须等待全局安全点
  2. 暂停拥有偏向锁的线程,判断锁对象是否处于被锁定状态
  3. 撤销偏向锁恢复到无锁(标志位为 01)或轻量级锁(标志位为 00)的状态

2.轻量级锁,加解锁中CAS具体分析:

企业微信截图_16564103567651.png

轻量级锁加锁和解锁的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的具体操作。

v2-c72642f76cf159537e6353ea7c883087_720w.jpg