Synchronized

https://www.cnblogs.com/pureEve/p/6421273.html
https://blog.****.net/javazejian/article/details/72828483
比较流畅的:https://blog.****.net/javazejian/article/details/72828483

一、基础知识介绍

A、实例对象,对象头

实例对象=对象头+数据+对齐位

对象头=mark Word+class reference=32位的锁状态标记+类类型指针

mark Word的状态如下图:
Synchronized

B、monitor
每个对象都会有一个monitor,在对象new 或者第一次被线程申请对象的时候产生,结构如下

Synchronized

C、内置锁的优化,或者锁的状态迁移

无锁态–>偏向锁–>轻量级锁—>重量级锁

二、简单讲讲锁之间的转换

前提:偏向锁用大部分是单线程场景下,减少monitor的切换
轻量级锁用在多线程交替执行同一个代码时,即枪的时候能够大概率抢到,因为抢不到马上就回升级成重量级锁,需要进行线程切换,开销大

第一步:
一个对象无锁状态,线程1尝试获取,发现无锁状态,直接获取到这个对象,并且将markWord标记自己的线程ID,且置为可偏向,

第二步:
线程1同时又来一次,因为是偏向的,查看是否当前的,是,则直接走代码

第三步:
线程2也来了,发现是偏向锁,并且被线程2占用了,则进行在markword进行线程IDCAS抢这个线程,抢到了,继续,没抢到,线程2直接挂起,线程1走第四步;

第四步:
线程1发现有线程2来抢了,等线程1或线程3到了安全点,线程1或者线程3(因为这中间可能被线程3抢到)被暂停,直接置为未锁定状态,是否偏向置为0,允许别人升级为轻量级锁
接下来,检测被暂停的线程状态

第五步:
发现线程已经结束了,则对象markword一直在未锁定
如果还没结束,则对这个线程进行轻量级锁的升级,第六步

第六步:
new 一个monitor(如果是第一次的话),monitor拷贝对象的hashCode,还有GC年代等。
然后CAS,尝试抢占,抢占的工作有:mark word 指针指向monitor,monitor中的owner指向当前线程ID,
CAS成功后,修改markword的状态为00表示轻量级锁
抢占不成功:直接将锁标记为重量级锁,即将线程4标记为重量级锁
告诉其他线程,你们不要抢了,直接阻塞掉

第七步:
自旋(默认10次,可能会根据上一次的表现进行加减,如果上一次多等了1、2次就等到了,则现在多自旋1、2次,如果上次等了很久都没等到,则直接减少自旋次数)

第八步:
自旋抢占成功,自己就变成了那个重量级锁
自旋抢占不成功,阻塞等待唤醒