synchronized锁膨胀过程
2021-06-24 17:13:49 3 举报
synchronized锁膨胀过程
作者其他创作
大纲/内容
01
执行同步代码块
获取偏向锁((thread id|epoch|age|1(是否偏向锁)|01(标记位)))
是
暂停原持有偏向锁的线程
释放锁
用于标记GC
将monitor的woner指向原持有轻量级锁的线程,并且锁对象MarkWord保存monitor指针,锁标记为10
唤醒那些被挂起的线程
原持有偏向锁的线程
当前线程获得轻量级锁(对象头的锁记录的指针指向当前线程|00标记位)
—
只需要比较thread ID
指向当前锁记录的指针prt to lock record
唤醒原持有偏向锁的线程
再尝试
从安全点继续执行
成功设置
原持有偏向锁线程释放锁(空|0(是否偏向锁)|01(标记位))
特征
升级为重量级锁
拷贝对象头中MarkWord到当前线程的锁记录lockrecord中
否
是否偏向锁
开启新一轮轻量级锁竞争
age
线程访问同步代码块
原持有偏向锁的线程的栈中分配锁记录
原持有偏向锁的线程达到安全点
原持有轻量级锁线程获得重量级锁(指向重量级锁monitor的指针|10标记位)
hash
Mutex Lock阻塞当前线程
1、问题当线程A 获取了偏向锁,此线程B进来了,走到了同步代码块前,此时是的锁是如何变化的,看到文章中:线程B CAS 失败会发起偏向锁撤销。 此处是线程A 升级为轻量级锁,还是重新争抢? 如果是重新争抢,失败的线程会怎样?答:线程A修改MarkWord中的信息,修改锁的标识为00,升级为轻量级锁;A已经持有偏向锁,从偏向锁升级为轻量级锁,是不需要再去重新争抢的,线程B会自旋尝试获取轻量级锁;
执行同步代码块结束
4、ThreadA在获得轻量级锁后,其RecordLock里存储着锁对象头的Mark word信息,将锁对象的Mark Word更新为指向Lock Record的指针,在ThreadB自旋失败后,进行锁膨胀,修改为重量级锁,这里有三个问题:1)ThreadB修改为重量级锁,是修改的 Lock Record中存储的Mark word的信息么?2)此时锁对象的Mark Word指向的Lock Record的指针是 ThreadB的么?3)在ThreadB将锁膨胀为重量级锁之后,正在执行中的ThreadA怎么处理?答:1)线程B膨胀为重量级锁,是基于Monitor了,不是再修改markword;2)所以第二个问题不存在;3)锁膨胀为重量级锁之后,ThreadA继续运行,直到运行结束。
检查MarkWord中记录的线程ID是否是当前线程
标记位(2bit)
可GC
轻量级锁00标记位
检查原持有偏向锁的线程状态
cas操作替换MarkWord线程id
暂停原持有轻量级锁的线程
原持有轻量级锁的线程达到安全点
cas操作尝试把monitor的owner字段设置为当前线程
bitfileds
开启新一轮重量级锁竞争
epoch
成功替换
未退出同步代码块
开始偏向锁撤销(等待锁竞争出现才释放锁的机制)
原持有轻量级锁的线程
00
指向重量级锁monitor的指针prt to heavyweight monitor
依赖mutex(操作系统的互斥)
1(是否偏向锁)
偏向锁
11
原持有偏向锁线程获得轻量级锁(对象头的锁记录的指针指向原持有偏向锁线程|00标记位)
thread ID
mark word
未活动状态/已退出同步代码块
cas自旋
10
拷贝对象头中的MarkWord到原持有偏向锁线程的锁记录中
当前锁状态
当前线程
当前线程获得重量级锁(指向重量级锁monitor的指针|10标记位)
0(是否偏向锁)
cas自旋达到一定次数依然没有成功
轻量级锁
重量级锁10标记位
notify
cas操作替换将对象头的MarkWord中的锁记录指针指向当前线程的锁记录
自旋
开始轻量级锁解锁
cas操作替换(1&2)1.将对象头的MarkWord中的锁记录指针是否指向当前线程2.拷贝在当前线程锁记录的MarkWord信息是否与对象头中的MarkWord一致
无锁
当前线程的栈中分配锁记录
1(是)
0(否)
3、 jvm 是不是会自行根据当前并发,直接选择是采用偏向锁、轻量级、重量级,还是必须是从偏向锁过渡到重量级锁? 答:偏向锁默认是不开启的,如果要开启可以用上面第(2)说的方法,不开启就默认先获取到轻量级锁,然后再升级到重量级锁,这其实是对锁的一种优化。因为加锁、释放锁的成本,要比自旋等待获取锁的成本高很多。
唤醒原持有轻量级锁的线程
重量级锁
5、线程B多次自旋失败后,将锁升级为重量级锁之后,线程A就直接拥有了这把重量级锁,然后Monitor对象中_owner存储的是线程A的地址指针,而线程B则加入到__EntryList队列中进行阻塞,等待被唤醒,那此时,锁对象里的对象头里的Mark Word信息是不会改变的,仍然存储的是A的指针,是等到线程A释放锁的时候再去将Mark Word里的锁标识进行修改么(修改为重量级锁10)答:Mark word存储的不再是轻量级锁中指向Lock Record的指针,升级为重量级锁之后存储的就是Monitor了。
状态
升级为轻量级锁
收藏
0 条评论
下一页