synchronized在Jdk1.6后的底层优化分析
JDK1.6 对synchronized锁的实现引入了大量的优化来减少锁操作的开销,如: 偏向锁、轻量锁、自旋锁、适应性自旋锁、锁消除、锁粗化 等等技术。
讲synchronized之前,先说一些知识点。
锁的本质是可以理解为更新一个标识,就synchronized而言,这个标识是存在对象头中。
64位Hotspot虚拟机中,对象头定义为12个字节(byte),一个字节是8位(bit),也就是对象头一共96位。也就是说其中一些位数就是用来存储我们锁标识的。
synchronized锁主要存在五种状态
(1)无锁不可偏向
无锁好理解,就是说这个对象没有被任何线程上锁。不可偏向的意思就是说这个对象不会偏向于某个线程(这句话涉及到偏向锁,看完后边回来就理解了)。
三种情况会产生无锁不可偏向状态
a. 关闭偏向锁
a. 偏向延迟 (eg:JVM启动时开启偏向延迟默认4s内所有对象都是无锁不可偏向状态。以为JVM在启动时有很多内置加锁操作,这些操作是不需要用到偏向锁的,偏向锁如果发生撤销、膨胀的话过程会耗费性能。这个时间和是否开启无锁可偏向状态都可以设置)
b. 对象计算hashcode之后是不可偏向的。对象头中已经存储hashcode的部分已经有了hashcode,这部分不能再被用来存储一部分线程id。
如果一个锁是不可偏向的,那么线程上锁时(没有竞争),会直接升级为轻量锁。
(2)无锁可偏向
对象没有被任何线程上锁,且可以被线程上锁持有。线程上锁后,会将线程id通过cas操作存储到markword中,升级为偏向锁。
(3)偏向锁
对象已经被线程上锁,markword前54位存储的上锁线程id。后三位101。当一个线程对这个对象上锁时,先检查对象头中的线程id是否与自己一致,一样的话线程就不需要进行同步。
加锁过程详细点解释就是:当一个线程访问同步块并获取锁时, 会在锁对象的对象头和栈帧中的锁记录里存储锁偏向的线程ID, 以后该线程进入和退出同步块时不需要进行CAS操作来加锁和解锁, 只需要简单的测试一下锁对象的对象头的MarkWord里是否存储着指向当前线程的偏向锁(线程ID是当前线程), 如果测试成功, 表示线程已经获得了锁; 如果测试失败, 则需要再测试一下MarkWord中偏向锁的标识是否设置成1(表示当前是偏向锁), 如果没有设置, 则使用CAS竞争锁, 如果设置了, 则尝试使用CAS将锁对象的对象头的偏向锁指向当前线程。
撤销过程: 偏向锁的撤销需要等到全局安全点(在这个时间点上没有正在执行的字节码). 首先会暂停持有偏向锁的线程, 然后检查持有偏向锁的线程是否存活, 如果线程不处于活动状态, 则将锁对象的对象头设置为无锁状态; 如果线程仍然活着, 则锁对象的对象头中的MarkWord和栈中的锁记录要么重新偏向于其它线程要么恢复到无锁状态, 最后唤醒暂停的线程(释放偏向锁的线程)
(4)轻量锁
轻量锁不是为了代替重量锁,本意是在没有多线程竞争的情况下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗,轻量锁的加锁和解锁都是使用的CAS,不需要向操作系统申请互斥量。但是如果存在锁竞争,除了互斥量还会有额外的CAS操作,轻量锁会被重量锁更慢,如果锁竞争激烈,会很快升级为重量锁。
(5)重量锁
重量级锁是基于 Monitor 机制,并且在 Monitor 中记录 hashCode
至于GC标记,如果这个对象被GC标记的话,这个标记也是存储在lock位的。
锁会随着竞争的激烈而逐渐升级。且升级不可降级,即 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁是单向的。 这种策略是为了提高获得锁和释放锁的效率。
一把锁第一次被线程持有的时候是偏向锁。如果这个线程再次加锁还是偏向锁,如果是别的线程来加锁,在交替执行没有资源竞争的情况下,锁会膨胀为轻量锁。如果是资源竞争,则膨胀为重量锁。
锁消除
锁消除理解起来很简单,它指的就是虚拟机即使编译器在运行时,如果检测到那些共享数据不可能存在竞争,那么就执行锁消除。锁消除可以节省毫无意义的请求锁的时间。需要开启逃逸分析。
锁粗化
原则上,我们在编写代码的时候,总是推荐将同步块的作用范围限制得尽量小,只在共享数据的实际作用域才进行同步,这样是为了使得需要同步的操作数量尽可能变小,如果存在锁竞争,那等待线程也能尽快拿到锁。大部分情况下,上面的原则都是没有问题的,但是如果一系列的连续操作都对同一个对象反复加锁和解锁,那么会带来很多不必要的性能消耗。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本