死磕synchronized五:系统剖析轻量级锁
哈喽,大家好,我是江湖人送外号[道格牙]的子牙老师。
近期准备写一个专栏:从Hotspot源码角度剖析synchronized。前前后后大概有10篇,会全网发,写完后整理成电子书放公众号供大家下载。对本专栏感兴趣的、希望彻彻底底学明白synchronized的小伙伴可以关注一波。电子书整理好了会通过公众号群发告知大家。我的公众号:硬核子牙。
本篇文章给大家分享关于轻量级锁的所有。在synchronized的所有锁类型中,轻量级锁是最简单的,但是这个简单是相对的,如果不具备一些底层的思维及学习底层的办法,它的源码也不是那么容易理解。
关于轻量级锁
首先说下什么情况会用到轻量级锁
- 延迟偏向期间,偏向锁还不可用,synchronized首先拿到的就是轻量级锁。即由无锁升级成轻量级锁
- 抢占偏向锁失败的线程会触发锁膨胀至轻量级锁。这里还需要考虑偏向锁重入的情况
- 膨胀成轻量级锁以后,如果后续的线程是在持有锁的线程执行结束后来抢锁,拿到的依然是轻量级锁。因为释放轻量级锁会恢复成无锁
- 膨胀成轻量级锁以后,如果是来抢锁,就会触发膨胀成重量级锁
再说下轻量级锁在对象头中的存在形式,如图。
针对大家的这么几个疑惑说明一下:
1、64位操作系统,内存地址是8字节,64位,为什么能用62位保存?因为内存地址虽然可以用64位,实际上只用了48位,还有16位是保留位,所以完全可以;
2、为什么可以用尾两位的00表示轻量级锁?言外之意就是说内存地址的尾两位一定是00吗?是的。64位操作系统,线程栈是按8字节为一个单位来用的,所以尾两位一定是00。
很多小伙伴还有一个疑惑,轻量级锁对象到底存放在虚拟机栈的什么位置?从这张图也可以看出来,是存放在栈帧的顶部。如果该方法被synchronized修饰,或者方法中有synchronized代码段,就会在栈帧的顶部创建一块叫monitor block区域,专门用来存放lock record。
接下来看下Hotspot源码是如何实现轻量级锁的、如何处理轻量级锁的重入、如何处理偏向锁膨胀成轻量级锁的兼容。
轻量级锁前的堆栈图
如果是synchronized修饰的方法,会先执行lock_method方法。这个方法做了三件事情:
- 根据是否是静态方法计算出锁对象,将锁对象的内存地址保持到rax寄存器中
- 在当前的栈帧中创建一个lock record,将锁对象的内存地址写入
- 调用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、死磕synchronized二:系统剖析延迟偏向篇一
3、死磕synchronized三:系统剖析延迟偏向篇二
4、死磕synchronized四:系统剖析偏向锁篇一
推荐阅读
1、今天聊点不一样的,百万年薪需要具备的能力
2、你是不是想问,那些技术大牛是如何练成的?我来告诉你
3、深入剖析Lambda表达式的底层实现原理
结语
其实技术这个行业真的不难,如果有人带,打底子1-2年,沉淀2-3年,足矣。我自己一步步探索,走得还算顺利,大概花了七年时间。
给大家看看我写好的
死磕synchronized五:系统剖析轻量级锁相关推荐
- yield方法释放锁吗_死磕Synchronized底层实现重量级锁
点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:farmerjohngit 链接:https://github.com/farmer ...
- 死磕Synchronized底层实现--偏向锁
注:本篇很长,请找个舒适的姿势阅读. 本文为synchronized系列第二篇.主要内容为分析偏向锁的实现. 偏向锁的诞生背景和基本原理在上文中已经讲过了,强烈建议在有看过上篇文章的基础下阅读本文. ...
- 死磕Synchronized底层实现
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源:http://suo.im/6h5g96 关于syn ...
- 死磕 synchronized 底层实现
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达今日推荐:2020年7月程序员工资统计,平均14357元,又跌了,扎心个人原创100W+访问量博客:点击前往,查看更多 来源 ...
- 死磕 java同步系列之redis分布式锁进化史
问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:R ...
- 死磕Java并发:深入分析synchronized的实现原理
本文转载自公众号: Java技术驿站 记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized.对于当时的我们来说,synchronized是如此的神奇且强大.我们赋予它一个名字& ...
- java中JAO_JVM内部细节之一:synchronized关键字及实现细节(轻量级锁Lightweight Locking)...
在C程序代码中我们可以利用操作系统提供的互斥锁来实现同步块的互斥访问及线程的阻塞及唤醒等工作.然而在Java中除了提供Lock API外还在语法层面上提供了synchronized关键字来实现互斥同步 ...
- Java Synchronized 偏向锁/轻量级锁/重量级锁的演变过程
前言 线程并发系列文章: Java 线程基础 Java 线程状态 Java "优雅"地中断线程-实践篇 Java "优雅"地中断线程-原理篇 真正理解Java ...
- Synchronized的原理及自旋锁,偏向锁,轻量级锁,重量级锁的区别
在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,Java S ...
最新文章
- 《科学》盘点2018可能被聚焦的研究领域
- Jquery Table 的基本操作
- rust(47)-key-value哈希-HashMap,BTreeMap,HashSet,BTreeSet
- linux read while 变量运算
- 让Keras更酷一些:中间变量、权重滑动和安全生成器
- Python全栈开发之3、数据类型set补充、深浅拷贝与函数
- 自底向上——知识图谱构建技术初探
- 欢迎关注我的微信公众账号:Linux技巧(微信号:irefactoring),一起学习Linux知识~~~...
- Jmeter之JSON Path Extractor的使用(JSON-handle下载安装和使用)
- 谷歌研究员发现新的 iOS 安全系统
- python画动态图-利用Python如何制作好玩的GIF动图详解
- Assigning retained object to weak property object will be released after assignment
- MFC功能扩展控件BCGSuite for MFC入门指南
- 项目管理的49个过程整理
- BZOJ2794 [Poi2012]Cloakroom [离线][DP]
- 能否被2整除引发的思考
- 解决:Excel 下拉项数据报 输入内容不能大于255个字符
- 家里装电线时,为啥说“走顶”比“走地”好
- explicit c++
- 计算机控制op,《计算机控制技术》