【转载】死磕synchronized五:系统剖析轻量级锁

哈喽,大家好,我是江湖人送外号[道格牙]的子牙老师。

近期准备写一个专栏:从Hotspot源码角度剖析synchronized。前前后后大概有10篇,会全网发,写完后整理成电子书放公众号供大家下载。对本专栏感兴趣的、希望彻彻底底学明白synchronized的小伙伴可以关注一波。电子书整理好了会通过公众号群发告知大家。我的公众号:硬核子牙

本篇文章给大家分享关于轻量级锁的所有。在synchronized的所有锁类型中,轻量级锁是最简单的,但是这个简单是相对的,如果不具备一些底层的思维及学习底层的办法,它的源码也不是那么容易理解。

关于轻量级锁

首先说下什么情况会用到轻量级锁

  1. 延迟偏向期间,偏向锁还不可用,synchronized首先拿到的就是轻量级锁。即由无锁升级成轻量级锁
  2. 抢占偏向锁失败的线程会触发锁膨胀至轻量级锁。这里还需要考虑偏向锁重入的情况
  3. 膨胀成轻量级锁以后,如果后续的线程是在持有锁的线程执行结束后来抢锁,拿到的依然是轻量级锁。因为释放轻量级锁会恢复成无锁
  4. 膨胀成轻量级锁以后,如果是来抢锁,就会触发膨胀成重量级锁

再说下轻量级锁在对象头中的存在形式,如图。

针对大家的这么几个疑惑说明一下:

1、64位操作系统,内存地址是8字节,64位,为什么能用62位保存?因为内存地址虽然可以用64位,实际上只用了48位,还有16位是保留位,所以完全可以;

2、为什么可以用尾两位的00表示轻量级锁?言外之意就是说内存地址的尾两位一定是00吗?是的。64位操作系统,线程栈是按8字节为一个单位来用的,所以尾两位一定是00。

很多小伙伴还有一个疑惑,轻量级锁对象到底存放在虚拟机栈的什么位置?从这张图也可以看出来,是存放在栈帧的顶部。如果该方法被synchronized修饰,或者方法中有synchronized代码段,就会在栈帧的顶部创建一块叫monitor block区域,专门用来存放lock record。

接下来看下Hotspot源码是如何实现轻量级锁的、如何处理轻量级锁的重入、如何处理偏向锁膨胀成轻量级锁的兼容。

轻量级锁前的堆栈图

如果是synchronized修饰的方法,会先执行lock_method方法。这个方法做了三件事情:

  1. 根据是否是静态方法计算出锁对象,将锁对象的内存地址保持到rax寄存器中
  2. 在当前的栈帧中创建一个lock record,将锁对象的内存地址写入
  3. 调用lock_object完成加锁

lock_method执行之后的堆栈图

lock_object

这个方法是模板解释器处轻量级锁的抢锁与重入处理逻辑。我们Java代码中的synchronized的轻量级锁都是在这里处理的。

这个方法全是汇编,我就不贴源码了,以伪代码的方式直接讲它的执行逻辑

这个方法执行后,如果不发生重入,堆栈图还是上面那个,不会变,只是将lock record的内存地址通过CAS写入到对象头中。

如果是重入,CAS是失败的,对象头不会发生变化,堆栈图会发生变化:1、如果是synchronized修饰方法这种情况,一个栈帧一个lock record,区别是第一个BasicLock.display_header不为0,其他都为0。为什么要这样呢?为了释放锁的时候识别哪个是最后一层。2、如果是synchronized代码块,一个栈帧中就有多个lock record,最后一层的BasicLock.display_header不为0,其他都为0。如图

轻量级锁解锁流程

轻量级锁的解锁逻辑比较简单:

1、判断是不是重入,如果是重入,直接return;

2、如果不是重入,意味着在解最后一层轻量级锁,需要将对象头恢复成无锁,这样后面的线程才能拿到轻量级锁。这个无锁头从哪来的?回忆一下上锁的时候,把rax寄存器中的无锁头写入了BasicLock.display_header,就是从这拿的;

3、其他情况就按重量级锁解锁处理。

偏向锁膨胀与重入

如果是偏向锁膨胀成轻量级锁,或者是重入的偏向锁膨胀成轻量级锁,Hotspot是如何处理的呢?直接看源码。注释写的很详细,就不重复啰嗦了。

至此就把轻量级锁相关的知识点讲完了。

系列文章

 1、JVM如何执行synchronized修饰的方法

2、系统剖析延迟偏向篇一

3、系统剖析延迟偏向篇二

4、系统剖析偏向锁篇一

推荐阅读

1、技术人如何才能拿到百万年薪?

2、为什么他们成为了技术大牛?

3、深入剖析Lambda表达式的底层实现原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值