基于jdk8u源码梳理,超详细synchronized粗化流程图及总结

上一次我们说了偏向锁的一些场景,但省略了偏向锁重定向、批量重定向、批量撤销等有意思而又复杂的内容(事实上,由于偏向锁内容确实复杂,jdk开发者在jdk15中已经将其废弃了,需要手动开启)。同时关于其他的粗化状态也并未提及。因此本文将基于jdk8u的c++源码,来梳理整个流程。
考虑到本文较为硬核,在此之前,你可能需要一些基础知识,首先还是上一张老图

synchronized的膨胀基本遵循 匿名偏向 》偏向锁 》轻量级锁 》重量级锁的过程。
偏向锁一旦被持有,即使持有的线程退出同步代码块。偏向锁也不会撤销或消失。此时若有第二个线程尝试获取锁,将直接升级至轻量级锁
上图里有个epoch字段,这个字段意为“纪元”,是为了判断当前偏向锁是否有效而引入的。我们需要知道,如果有一个类名为ClassA,除了依据ClassA new出来的实例对象外,ClassA本身也有个类对象,一般情况下,类对象的epoch是最新的,各实例对象的epoch和类对象的epoch保持一致,当某个实例对象发现自己的epoch落后了,代表它的偏向锁失效,此时可以重新偏向其他线程。
重量级锁与前面几种锁有本质不同,涉及到线程的阻塞,它并非通过栈和栈上标记实现,而是基于c++里的objectMonitor对象实现,我们在java中看到Object类里的wait()、notify()等方法其实是objectMonitor的方法,因此调用这些方法时,无论对象原本是什么状态,都会直接进入重量级锁状态
更详细的膨胀过程,和相关说明都在流程图中,图是基于jdk8u的c++源码整理出来的,说是全网最全最细也不为过。图中还编写了一些总结,希望能帮大家梳理通思路。至于重量级锁后的锁获取分析,会在之后推出。
(声明:因时间和本人水平限制,难免有所错漏,如果发现问题,欢迎及时指正)
