Synchronized锁的升级

无锁

Synchronized锁的升级_第1张图片

偏向锁

Synchronized锁的升级_第2张图片

加锁过程

偏向锁标志位置1

对象头中的标志位默认为“01”,即偏向模式

使用 CAS 操作 让锁对象的对象头的 偏向线程 id 指向当前线程 id

释放锁过程

偏向锁的释放只有有竞争时才会释放锁。释放锁只能发生在全局安全点(这个时间点是上没有正在执行的代码)

暂停拥有偏向锁的线程,判断锁对象是否处于被锁定状态

撤销偏向锁,恢复到无锁或轻量级锁的状态

锁重入

当 锁对象的对象头的 偏向线程 id 指向当前线程 id时,直接执行同步块的代码

锁竞争

当另一个线程获取锁时发现偏向线程 id和自己不一样,需要再测试一下Mark Word中偏向锁的标识是否设置成1(是否还是偏向锁)

如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程

CAS 设置失败则膨胀为轻量级锁

Synchronized锁的升级_第3张图片

轻量级锁

Synchronized锁的升级_第4张图片

获取偏向锁失败后,尝试升级为轻量级锁

加锁过程

当前线程内部创建锁记录(Lock Record)将 markwork 内容记录下来,将Object reference 指向对象

使用 CAS 操作 将锁对象的对象头的 markwork 的内容替换为锁记录的地址和状态00(表示轻量级锁)

记录锁状态为轻量级锁 00

释放锁过程

当线程退出同步代码块时

参照锁记录表,删除最新的记录,

当记录中的markwork部分不为 null 时,将保存在锁记录中的markwork 的内容替换到对象头中

锁重入

再次增加一个锁记录(Lock Record),新的锁记录markwork部分为 null

锁竞争

首先进行自旋,自旋一定次数后(默认10次)还无法获得锁,则膨胀为重量级锁

JDK 1.7 之后,引入了适应性自旋,这次自旋获取到锁了,自旋的次数就会增加;这次自旋没拿到锁,自旋的次数就会减少

Synchronized锁的升级_第5张图片

重量级锁

Synchronized锁的升级_第6张图片

无法获得轻量级锁时,膨胀为重量级锁,重量级锁是依赖对象内部的monitor锁来实现的,而monitor又依赖操作系统的MutexLock(互斥锁)来实现的

加锁过程

锁标志位置为10

创建一个ObjectMonitor对象

在锁对象的markword中记录下ObjectMonitor的指针

monitor的 _owner指向当前线程

monitor计数器+1

释放锁过程

将monitor计数器-1

当monitor计数器为0则monitor中_owner变量就会清空

同事唤醒等待中的其他线程,让他们竞争锁

锁重入

monitor计数器+1

锁竞争

如果monitor计数器不为0则加入到等待队列,等到持有所得线程释放锁后被唤醒进行竞争

图解

Synchronized锁的升级_第7张图片

https://www.likecs.com/show-205297476.html

https://www.jianshu.com/p/d53bf830fa09

kxmguyv-1656175183618)]

https://www.likecs.com/show-205297476.html

https://www.jianshu.com/p/d53bf830fa09

https://blog.csdn.net/qq_38826019/article/details/119307386

你可能感兴趣的:(工作学习记录,java,jvm,开发语言)