14 | Java虚拟机是怎么实现synchronized的?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
Java虚拟机中的锁机制是通过synchronized关键字实现的,包括重量级锁、轻量级锁和偏向锁。重量级锁会阻塞、唤醒请求加锁的线程,适用于多个线程竞争同一把锁的情况。轻量级锁采用CAS操作,针对多个线程在不同时间段申请同一把锁的情况。而偏向锁则适用于锁仅会被同一线程持有的情况。文章介绍了这些锁的实现原理和特点,并提供了实践环节来验证偏向锁的一些传闻。读者可以通过参数来观察各类锁的个数,以及验证调用Object.hashCode()对偏向锁的影响。这篇文章深入浅出地介绍了Java虚拟机中synchronized关键字的实现方式,适合想要深入了解Java虚拟机锁机制的读者阅读。
《深入拆解 Java 虚拟机》,新⼈⾸单¥59
全部留言(79)
- 最新
- 精选
- 钱恩,今天才补上小结,因为听不明白了,后来反复听以及补上锁的相关知识才有点明白。 我认为雨迪确实应该补上点图,这样才更容易理解,否则确实抽象,另外,我觉得讲解的次序有点小问题。 如果这样讲就更容易理解了(个人见解) 1:讲解一下锁的本质,锁到底是个什么东西?锁的特点容易理解,毕竟都见过摸过用过 2:讲解一下锁的分类和特点,什么表锁、行锁、自旋锁、可重用锁、轻量锁、重量锁、阻塞锁、线程锁、进程锁、分布式锁、偏向锁等等吧!都是站在不同的角度或层级根据锁的特点,为了好区分给锁起的名字 3:讲解一下JVM中的各种锁,讲解一下他们的特点和实现,然后讲解一下咱们本节的主角是属于哪一种或哪几种锁 4:我的理解,锁的本质-在程序世界里是一种保证资源正确竞争的机制,如果没有对同一资源竞争也就没有了锁存在的意义,在计算世界中资源引起竞争的核心基本是空间,有其是计算机的内存空间,当然数据肯定也是一种引起激烈竞争的资源,不过往往会体现到空间上去,因为计算机中的数据必定存于某空间地址之中的 5:感觉明白可重用锁的实现原理了,这个也是雨迪讲的最细致的一种实现方式,恩,非常感谢🙏
作者回复: 多谢建议! 本文的讲解流程是从通用锁算法到针对特殊情况的锁算法来的。一开始monitorenter是用重型锁的,然后为了针对没有竞争锁的情况有了轻型锁,再然后为了针对只有一个线程持有某个锁的情况有了偏向锁。
2018-09-01429 - 爪哇夜未眠太抽象了,老师能画点儿图吗……
作者回复: 不好意思哈,因为网上有很多图,忘了放个链接了。 你可以参考wiki.openjdk.java.net/display/HotSpot/Synchronization中的图。
2018-08-2224 - Shine“当进行解锁操作时,如果当前锁记录(你可以将一个线程的所有锁记录想象成一个栈结构,每次加锁压入一条锁记录,解锁弹出一条锁记录,当前锁记录指的便是栈顶的锁记录)的值为 0,则代表重复进入同一把锁,直接返回即可。” 这种情况也需要弹出当前锁记录的吧? 不然锁记录一直是0不变了。 如果是我这样理解的话,重复获取同一把锁的话,不是简单地清零,而应该是把0作为一条新的锁记录压入栈顶。 不知道我这样理解对不?请老师指点
作者回复: 对的!赞
2018-08-26218 - NEO🍋老师关于偏向锁有个疑问 “它针对的是锁仅会被同一线程持有的情况。” 如果只有一个线程持有锁 还有必要加锁吗?
作者回复: 哈,这个属于应用程序的问题,JVM只是观察到这种情况,并尝试做出优化。 有一种可能,就是很长一段时间内,只有一个线程频繁加锁,后面换成另外的线程,这样前面那段时间可以用偏向锁。
2018-08-2213 - Geek_987169老师请教个问题: 1:锁从偏向一直到重量级的过程是"单向不可逆"的,这个"单向不可逆"是限制在对象的整个生命周期,还是在对象到达了某个状态后再次有线程使用其作为锁对象还会继续重复这个过程?从每撤销一次对象的epoch值就会+1,而这个+1代表的就是偏向锁升级为轻量级锁,而每个对象又维护了一个epoch值代表对象撤销次数(偏向锁->轻量级锁次数),是不是就代表这个锁升级的过程会在不同的时间段重复发生n词? 2:为什么要设置一个最大的撤销次数(epoch值),意义在哪里?
作者回复: 1. 单向不可逆 针对一个对象的整个生命周期。 epoch+1发生在多次同一类型的实例的偏向锁撤销之后,存放在类型(Class)那里的。 2. 当频繁检测到某个类的实例出现撤销偏向锁的,就代表这个类不适合用来搞偏向锁。
2018-10-188 - 唯一老师,问一下加锁实际上都是加在当前线程吗
作者回复: 这个说法有点歧义。 按我的理解,你应该在问是否为当前线程获得这把锁?那么答案是对的,一直是当前线程获得这把锁。 另外,锁是加在目标锁对象上的。
2018-08-226 - 何yuan一直认为synchronized是重量锁,是否也不一定?jvm处理的时候是先将当偏向锁处理,然后慢慢膨胀为重量级锁的是吗?
作者回复: 默认情况下是的。以前有个延缓毫秒数-XX:BiasedLockingStartupDelay,一开始用轻量级锁,在启动四秒之后才开始用偏向锁。我记得Java 9还是10默认值改为0了。
2018-08-2226 - 木心很多文章说 自旋 是在轻量级锁中发生的 《Java并发编程的艺术》 但是在这里 自旋 是在重量级锁中 这个怎么解释呢? https://www.aimoon.site/blog/2018/05/21/biased-locking/
作者回复: 自旋本质是空转cpu等待,只有在别人拿着锁,自己请求锁的情况下发生。偏向锁无需此步骤,栈锁别人没有持有锁,也不需要自旋
2019-11-2865 - Leon Wong老师你好,本课程在介绍轻量级锁的时候,没提及轻量级锁在其他线程占用改锁的的时候,是否会进入自旋状态,我先前的理解是,轻量级锁在被其他线程占用的时候,会进入短暂的自旋状态,当自旋达到一定的阈值后,膨胀为重量级锁,阻塞当前线程,不知道我这么理解是否正确?
作者回复: 我印象中不会自旋,直接膨胀。 轻量级锁的假设是,不同线程拿同一把锁的时间没有overlap。一旦有了overlap,即需要竞争锁的情况,那么假设失效,需要膨胀为重量锁。 如果乐观点的话,猜测只有这一次假设失效,那也可以自旋一会再膨胀。不过我记得没有这么乐观。 你可以自己读hotspot的源代码,share/runtime/synchronizer.cpp ObjectSynchronizer:fast_enter
2018-09-1734 - 贾智文假设当前锁对象的标记字段为 X…XYZ,Java 虚拟机会比较该字段是否为 X…X01。 老师请问这个x……x01是什么,根据什么来的呢?
作者回复: 这里可能没写清楚。我指的是标记字段的bits是否为X..X01,其中X..X是从原本的标记字段拷过来的。
2018-08-2234