Synchronized锁升级的原理和过程
2021-07-26 09:57:03 14 举报
Synchronized锁升级的原理和过程
作者其他创作
大纲/内容
object
CAS将对象头的Thread ID改为当前线程ID
是
失败
对齐填充:自动内存管理系统要求对象起始地址必须是8字节的整数倍
hash code
是当前线程ID
是否是偏向锁?
开始轻量级锁解锁
10
当前程的栈中分配锁记录空间
原持有偏向锁的线程获得轻量级锁指向栈中锁记录的指针 | 00
未活动/已退出同步代码块
以同步代码块的锁升级为例,当执行到同步代码块时,线程会先去判断锁对象头的Mark Word中的锁标志位是什么,锁标志位(01,00,10,11)。判断锁标志位:01表示为无锁或偏向锁,所以需要再去判断是否是偏向锁比特位,0表示无锁,1表示偏向锁,是偏向锁的话会用cas去替换对象头中Mark Word中的Thread ID,成功替换则当前线程获取偏向锁成功,cas替换失败则表示出现了锁竞争,需要撤销偏向锁,等到原持有偏向锁的线程到达全局安全点,暂停原持有偏向锁的线程,再去判断原持有偏向锁线程的执行状态,未活动或者是已执行完同步代码块则释放锁,变为无锁状态;原持有偏向锁未退出同步代码块则在原持有偏向锁的线程栈中开辟一块锁记录空间并把锁对象的Mark Word复制到锁记录空间,锁对象Mark Word中锁记录中间的指向刚开辟的锁记录空间,原持有偏向锁的线程就获取了轻量级锁。当前线程也会在栈中开辟以块锁记录空间,同样地把Mark Word复制一份到锁记录空间,通过自旋CAS来尝试去替换锁对象的锁记录指针为当前锁记录的指针,成功则表示获取到轻量级锁,去执行对应的同步代码块。jvm回去判断尝试次数,会有一个自适应自旋的过程,当发现很久都不能加锁成功时,就会去升级为重量级锁。
00
同步代码块
mutex挂起当前线程,等待操作系统调度
获得偏向锁Thread ID | epoch | age | 1 | 01
未退出同步代码块
偏向锁线程ID
暂停原持有偏向锁的线程
拷贝对象头的Mark Word到锁记录空间
为什么需要锁升级这个过程?为了提高程序的响应速度,因为重量级锁是通过monitor来实现的,涉及到了操作系统调度线程、上下文切换、用户态与内核态的切换、线程的阻塞与唤醒要进行上下文的存储与恢复,需要消耗的资源多,小并发量短时间来说相对于cas时间长,但是大并发量与超大并发量下cas会有大量空转的情况且消耗cpu资源,所以这时候就需要锁升级,让线程挂起,等待操作系统调度。
释放锁
实例数据
升级为轻量级锁
CAS操作1&21.Mark Word中锁记录的指针是否仍然指向当前线程锁记录2.拷贝在当前线程锁记录中Mark word信息与锁对象中Mark Work是否一致
类型指针(指向class)
当前对象头的Mark Word的Thread ID
执行同步代码块
成功
撤销偏向锁
唤醒被挂起的线程,开始新一轮的锁竞争
偏向锁时间戳
自旋次数
不是当前线程ID
01
锁状态
原持有偏向锁线程的栈中分配锁记录空间
达到一定次数都没有成功
唤醒原持有偏向锁的线程
成功说明没有升级为重量级锁
自旋/自适应自旋
获得锁执行代码块
对象头
检查原持有偏向锁线程的状态
锁状态标记
失败说明已经升级为了重量级锁
从安全点继续执行同步代码块
升级为重量级锁
Mark Word对象自身运行时的数据
GC分代年龄
原持有偏向锁线程释放锁空 |(是否偏向锁)0 |(标志位)01无锁状态
拷贝对象头的Mark Word到锁记录空间将对象头的Mark word中锁记录指针指向当前线程锁记录
升级为重量级锁指向monitor对象的指针 | 10
原持有偏向锁的线程到达安全点
CAS将对象头的Mark word中锁记录指针指向当前线程锁记录
对象分代年龄
数组长度(数组对象独有)
0 条评论
回复 删除
下一页