死磕synchronized五:系统剖析偏向锁篇二原创
哈喽,我是子牙。十余年技术生涯,一路披荆斩棘从技术小白到技术总监到JVM专家到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核。特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。
手撸过JVM、内存池、垃圾回收算法、synchronized、线程池、NIO…
近期准备写一个专栏:从Hotspot源码角度剖析synchronized。前前后后大概有10篇,会全网发,写完后整理成电子书放公众号供大家下载。对本专栏感兴趣的、希望彻彻底底学明白synchronized的小伙伴可以关注一波。电子书整理好了会通过公众号群发告知大家。我的公众号:硬核子牙。
废话不多说,接上篇,开始卷Hotspot源码。如果你还没看上篇,墙裂都建议你先看一下。
注意:本篇文章是针对synchronized修饰方法这种情况写的。关于synchronized代码段,其实除了lock record外,差别不大。
偏向锁前的堆栈图
如果是synchronized修饰的方法,会先执行lock_method方法。这个方法做了三件事情:
-
根据是否是静态方法计算出锁对象,将锁对象的内存地址保持到rax寄存器中
-
在当前的栈帧中创建一个lock record,将锁对象的内存地址写入
-
调用lock_object完成加锁
lock_method执行之后的堆栈图
这个图对于后面理解偏向锁的膨胀、撤销及轻量级锁至关重要。
lock_object
这个方法这里有个判断,如果启用了偏向锁就调用biased_locking_enter。如果没有启用,或者biased_locking_enter执行结束回来,后面代码是抢占轻量级锁、轻量级锁重入、膨胀成重量级锁逻辑。后面讲轻量级锁、重量级锁细讲。
biased_locking_enter
这个方法全是汇编,我就不贴源码了,以伪代码的方式直接讲它的执行逻辑
这个方法是理解偏向锁的核心方法之一,小伙伴们一定要多看多想多悟,悟透,不然学到后面一团糟。
模板解释器那块,关于偏向锁的逻辑就详细地讲完了。接下来咱们以不同的锁类型进入偏向锁逻辑为例梳理偏向锁的执行逻辑,正好把fast_enter那块的逻辑串起来。
如果是匿名偏向锁
如果当前对象的锁状态是匿名偏向状态,按照前面讲的,会出现两种情况:CAS成功抢到了偏向锁,进入临界区执行代码。CAS失败进入slow_case。接下来把slow_case整个逻辑讲一下。
看代码执行顺序
revoke_bias
理解这个方法,堆栈图就要派上用场了
讲到这再回顾下上篇文章的这段话,是不是理解得更深刻了
抢偏向锁
这种情况跟多线程抢偏向锁抢锁失败的情况是一样的,就不重复讲了。
至此,偏向锁的核心逻辑就讲完了。其他的知识点,感兴趣的小伙伴,可以基于理解我分享的这些,去自行研究。相信小伙伴们都能征服synchronized。
系列文章
推荐阅读
你好,我是子牙。十余年技术生涯,一路披荆斩棘从小白到技术总监到大厂中间件到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核及特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。不考虑交个朋友吗?关注硬核子牙: