Synchronized

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

一、基础知识介绍

A、实例对象,对象头

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

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

mark Word的状态如下图:
这里写图片描述

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

这里写图片描述

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

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

三、锁的状态

为什么要优化?
切换时需要从用户态转换到核心态,开销大。

偏向锁:
场景:锁不仅不存在多线程竞争,而且总是由同一线程多次获得
没有抢占,没有多线程

解决:为了减少同一线程获取锁的代价而引入偏向锁。
怎么抢:此时的锁,有个线程ID标记在对象头中,只要进行CAS抢占即可

轻量级锁:有多线程,但是没有抢占,时间错位
场景:线程抢占,没有竞争,如:线程交替执行同步块的场合
解决:
怎么抢:

自旋锁: 有多线程,有抢占,但是冲突不会太久。很快就能抢占
线程持有锁的时间都不会太长,如果直接挂起操作系统层面的线程可能会得不偿失

死循环几次(50到100,经验刷新)

重量级锁:有多线程,有抢占,而且长时间抢占不到。
抢占的线程要重新new 一个monitor2(监视器),让monitor2去和原来占有锁的线程的monitor1进行CAS抢占。这就需要用户态切换成核心态,开销大

锁消除:
虽然你写了synconizied,但是会优化掉这段代码,如果这段代码确实不会造成线程不安全

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

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

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

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

第三步:
线程2也来了,发现是偏向锁,并且被线程1占用了,则进行在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次,如果上次等了很久都没等到,则直接减少自旋次数)

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

综合:
偏向锁认为没有竞争,不要进行cas抢线程,,轻量锁认为小概率事件,cas进行抢线程,自旋锁认为马上可以等到,重量锁等待唤醒,排队抢占

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值