14 | Java虚拟机是怎么实现synchronized的?
14 | Java虚拟机是怎么实现synchronized的?
讲述:郑雨迪
时长14:27大小6.62M
重量级锁
轻量级锁
偏向锁
总结与实践
赞 12
提建议
精选留言(75)
- 钱2018-09-01恩,今天才补上小结,因为听不明白了,后来反复听以及补上锁的相关知识才有点明白。 我认为雨迪确实应该补上点图,这样才更容易理解,否则确实抽象,另外,我觉得讲解的次序有点小问题。 如果这样讲就更容易理解了(个人见解) 1:讲解一下锁的本质,锁到底是个什么东西?锁的特点容易理解,毕竟都见过摸过用过 2:讲解一下锁的分类和特点,什么表锁、行锁、自旋锁、可重用锁、轻量锁、重量锁、阻塞锁、线程锁、进程锁、分布式锁、偏向锁等等吧!都是站在不同的角度或层级根据锁的特点,为了好区分给锁起的名字 3:讲解一下JVM中的各种锁,讲解一下他们的特点和实现,然后讲解一下咱们本节的主角是属于哪一种或哪几种锁 4:我的理解,锁的本质-在程序世界里是一种保证资源正确竞争的机制,如果没有对同一资源竞争也就没有了锁存在的意义,在计算世界中资源引起竞争的核心基本是空间,有其是计算机的内存空间,当然数据肯定也是一种引起激烈竞争的资源,不过往往会体现到空间上去,因为计算机中的数据必定存于某空间地址之中的 5:感觉明白可重用锁的实现原理了,这个也是雨迪讲的最细致的一种实现方式,恩,非常感谢🙏展开
作者回复: 多谢建议! 本文的讲解流程是从通用锁算法到针对特殊情况的锁算法来的。一开始monitorenter是用重型锁的,然后为了针对没有竞争锁的情况有了轻型锁,再然后为了针对只有一个线程持有某个锁的情况有了偏向锁。
共 4 条评论29 - 爪哇夜未眠2018-08-22太抽象了,老师能画点儿图吗……
作者回复: 不好意思哈,因为网上有很多图,忘了放个链接了。 你可以参考wiki.openjdk.java.net/display/HotSpot/Synchronization中的图。
22 - QlDoors2018-11-21练习试了无数遍,都没有偏向锁,后来上网查才发现需要加-XX:BiasedLockingStartupDelay=0。 http://zhizus.com/2018-09-03-%E5%81%8F%E5%90%91%E9%94%81.html 注意:Hotspot虚拟机在开机启动后有个延迟(4s),经过延迟后才会对每个创建的对象开启偏向锁。我们可以通过设置下面的参数来修改这个延迟,或者直接sleep一段时间-XX:BiasedLockingStartupDelay=0展开共 1 条评论20
- 谢阳2018-08-23如果不是 X…X01,那么有两种可能。第一,该线程重复获取同一把锁。此时,Java 虚拟机会将锁记录清零,以代表该锁被重复获取。第二,其他线程持有该锁。此时,Java 虚拟机会将这把锁膨胀为重量级锁,并且阻塞当前线程。 老师这段不太明白。1 锁记录清零怎么理解?改变锁对象的标记字段吗?2 锁膨胀的时候其他线程还持有锁对象吧,这个时候膨胀会具体做什么操作?如果操作了锁对象的标记字段会影响稍后释放锁的cas吗展开共 2 条评论18
- Shine2018-08-26“当进行解锁操作时,如果当前锁记录(你可以将一个线程的所有锁记录想象成一个栈结构,每次加锁压入一条锁记录,解锁弹出一条锁记录,当前锁记录指的便是栈顶的锁记录)的值为 0,则代表重复进入同一把锁,直接返回即可。” 这种情况也需要弹出当前锁记录的吧? 不然锁记录一直是0不变了。 如果是我这样理解的话,重复获取同一把锁的话,不是简单地清零,而应该是把0作为一条新的锁记录压入栈顶。 不知道我这样理解对不?请老师指点展开
作者回复: 对的!赞
共 2 条评论16 - Monday2020-07-13听了N次,仔细读了一遍,还是不够。有同样情况的,赞起12
- NEO🍋2018-08-22老师关于偏向锁有个疑问 “它针对的是锁仅会被同一线程持有的情况。” 如果只有一个线程持有锁 还有必要加锁吗?
作者回复: 哈,这个属于应用程序的问题,JVM只是观察到这种情况,并尝试做出优化。 有一种可能,就是很长一段时间内,只有一个线程频繁加锁,后面换成另外的线程,这样前面那段时间可以用偏向锁。
12 - Geek_9871692018-10-18老师请教个问题: 1:锁从偏向一直到重量级的过程是"单向不可逆"的,这个"单向不可逆"是限制在对象的整个生命周期,还是在对象到达了某个状态后再次有线程使用其作为锁对象还会继续重复这个过程?从每撤销一次对象的epoch值就会+1,而这个+1代表的就是偏向锁升级为轻量级锁,而每个对象又维护了一个epoch值代表对象撤销次数(偏向锁->轻量级锁次数),是不是就代表这个锁升级的过程会在不同的时间段重复发生n词? 2:为什么要设置一个最大的撤销次数(epoch值),意义在哪里?展开
作者回复: 1. 单向不可逆 针对一个对象的整个生命周期。 epoch+1发生在多次同一类型的实例的偏向锁撤销之后,存放在类型(Class)那里的。 2. 当频繁检测到某个类的实例出现撤销偏向锁的,就代表这个类不适合用来搞偏向锁。
7 - 贾智文2018-08-22文中说轻量级锁因为内存对齐所以标识位是00,那么为什么重量级锁的时候,存储内容也是指针,却没有内存对齐呢?共 1 条评论6
- 第9根烟2019-01-08这边验证了Object.hashCode() 不会关闭该对象的偏向锁。。不知道最后答案是什么?哪里有全篇的课后作业的答案?4
- 木心2019-11-28很多文章说 自旋 是在轻量级锁中发生的 《Java并发编程的艺术》 但是在这里 自旋 是在重量级锁中 这个怎么解释呢? https://www.aimoon.site/blog/2018/05/21/biased-locking/
作者回复: 自旋本质是空转cpu等待,只有在别人拿着锁,自己请求锁的情况下发生。偏向锁无需此步骤,栈锁别人没有持有锁,也不需要自旋
共 6 条评论4 - 唯一2018-08-22老师,问一下加锁实际上都是加在当前线程吗
作者回复: 这个说法有点歧义。 按我的理解,你应该在问是否为当前线程获得这把锁?那么答案是对的,一直是当前线程获得这把锁。 另外,锁是加在目标锁对象上的。
4 - 何yuan2018-08-22一直认为synchronized是重量锁,是否也不一定?jvm处理的时候是先将当偏向锁处理,然后慢慢膨胀为重量级锁的是吗?
作者回复: 默认情况下是的。以前有个延缓毫秒数-XX:BiasedLockingStartupDelay,一开始用轻量级锁,在启动四秒之后才开始用偏向锁。我记得Java 9还是10默认值改为0了。
共 2 条评论4 - 加载中……2019-02-26您好,文章写的挺好,读完有个问题想请教下: 当t1线程获取了某个对象锁(lock1)的偏向锁,还没执行完的时候,另外一个线程t2也尝试获取这个对象锁(lock1),我看文章上说需要撤销偏向锁,等到达安全点的时候,再将偏向锁替换成轻量级锁。 我有个问题:两个线程同时竞争同一把锁的情况,轻量级锁也解决不了吧,只能用重量级锁解决吧?为什么还要替换成轻量级锁呢?展开3
- Leon Wong2018-09-17老师你好,本课程在介绍轻量级锁的时候,没提及轻量级锁在其他线程占用改锁的的时候,是否会进入自旋状态,我先前的理解是,轻量级锁在被其他线程占用的时候,会进入短暂的自旋状态,当自旋达到一定的阈值后,膨胀为重量级锁,阻塞当前线程,不知道我这么理解是否正确?
作者回复: 我印象中不会自旋,直接膨胀。 轻量级锁的假设是,不同线程拿同一把锁的时间没有overlap。一旦有了overlap,即需要竞争锁的情况,那么假设失效,需要膨胀为重量锁。 如果乐观点的话,猜测只有这一次假设失效,那也可以自旋一会再膨胀。不过我记得没有这么乐观。 你可以自己读hotspot的源代码,share/runtime/synchronizer.cpp ObjectSynchronizer:fast_enter
共 3 条评论3 - 贾智文2018-08-22假设当前锁对象的标记字段为 X…XYZ,Java 虚拟机会比较该字段是否为 X…X01。 老师请问这个x……x01是什么,根据什么来的呢?
作者回复: 这里可能没写清楚。我指的是标记字段的bits是否为X..X01,其中X..X是从原本的标记字段拷过来的。
3 - ゞ、今生绝恋丶2019-04-08雨迪老师,我有个疑问:假设线程A加锁,CAS将锁对象对象头替换成指向线程A的Lock Record的地址,在这里,原值:对象mark word中的内容,也就是hashcode,期望值:本线程Lock Record地址,对象:锁对象,在替换成功后我们说线程A获得了锁,OK,线程A开始执行同步代码块,在它执行完之前,线程B来获取锁,发现属于轻量级锁标志,于是CAS替换mark word,此时CAS的原值仍然为为锁对象的mark word吧,而此时锁对象mark word中记录的不再是hashcode而是指向线程A的Lock Record的地址,但是对于CAS它管你对象头存的是什么,现在获取到什么,什么就是原值,于是:原值:对象头中指向线程A中LR的地址,期望值:线程B中LR(目前对他来说,是将锁对象中指向线程A中LR的地址存入本线程LR)的地址,目标对象:锁对象,怎么会CAS不成功?于是现在线程B也获取到锁,两个线程都会在执行同步代码块!我觉得我理解的哪块不对?展开共 3 条评论3
- javaadu2018-08-24你好,例子运行了,没看出啥不同,只有“fast path lock entries”这个对应的数值不同,slow path lock entries一直是2,其他的都是0。 建议作者给出自己的实验截图,方便我们对比2
- (^o^)2018-08-22Synchronized某个对象时,这个对象的锁先是偏向锁,后根据具体竞争情况先升级为轻量级锁再升级为重量级锁吗?共 1 条评论2
- 林QC2018-08-22当声明 synchronized 代码块时,编译而成的字节码将包含 monitorenter 和 monitorexit 指令。~~老师,标记在方法上也有这两个指令吗?
作者回复: 没有,方法有ACC_SYNCHRONIZED标志符
2