Sychronized锁升级全解
2020-06-16 10:15:54 0 举报
Sychronized锁升级源码级流程解析流程图
作者其他创作
大纲/内容
若当前线程获取过,则说明当前线程再次进入monitor,即重入锁,执行_recursions ++ ,记录重入的次数;
失败
执行啊执行
是
唤醒线程A继续执行
成功
在omAlloc方法中会先从线程私有的monitor集合omFreeList中分配对象,如果omFreeList中已经没有monitor对象,则从JVM全局的gFreeList中分配一批monitor到omFreeList中。
获得偏向锁阶段
返回
线程A的锁升级同线程B
判断当前线程是否处于完成状态(是否存在)
判断是否开启偏向锁(UseBiase dLocking)
判断锁对象头MarkWord
判断当前markOopDesc状态
线程C
这里需要注意一点,虽然是自旋操作,但不会一直占用cpu资源,每隔一段时间会通过os::NakedYield方法放弃cpu资源,或通过park方法挂起;如果其他线程完成锁的膨胀操作,则退出自旋并返回;
通过CAS操作尝试吧monitor的_owner( 指向获得objectMonitor的线程或者 BasicLock对象)设置为当前线程
失败则有其他线程进行竞争
调用revoke_and_rebias()方法来获取当前偏向锁的状态(可能为撤销或撤销后重偏向,则返回,否则,执行slow_enter锁升级)
获取锁
为INFLATING
升级重量锁(ObjectSynchronizer::inflate)
通过CAS原子指令设置mark中JavaThread为当前线程ID
锁升级阶段
执行完成(monitorexit)
进入安全点(safe point)
CAS成功?
自旋等待
轻量锁阶段
把mark保存到BasicLock对象的_displaced_header字段;
成功释放锁
之前_owner指向的BasicLock在当前线程栈上,说明当前线程是第一次进入该monitor,设置_recursions为1,_owner为当前线程,该线程成功获得锁并返回;
撤销偏向锁
竞争重量锁
竞争到锁,执行同步代码
CAS是否成功
再次重试获取锁
获取线程堆栈中的Displaced Mark Word
如果当前线程拥有轻量级锁,那么通过CAS尝试把Displaced Mark Word替换到当前锁对象的Mark Word(CAS)
升级为轻量锁
倘若变为无锁,线程B正常获取偏向锁,不升级(此处不再讨论)
说明同一时刻其它线程已经将Mark Word设置为markOopDesc:INFLATING,当前线程进行自旋等待膨胀完成
通过CAS尝试把monitor的_owner字段设置为当前线程;
进行锁膨胀(升级)至重量锁
检测锁对象头MarkWord
获取当前线程拥有的锁对象信息,将当前锁对象的displaced header复制到线程堆栈中,且锁对象头指向堆栈的displaced header(CAS)。
获取当前线程拥有的锁对象信息,将当前锁对象的displaced header复制到线程堆栈中,且锁对象头MarkWord指向堆栈的displaced header(CAS)。
进入临界区并执行
否
锁状态变为01(无锁)或允许重偏向但偏向线程ID为空。
BiasedLocking设置为BIAS_REVOKED
如果当前为轻量锁,锁标志位为00
1、当前线程在栈中分配Lock Record;2、复制对象头的mark word到Lock Record;3、尝试将mark word指针指向当前Lock Record(CAS操作)4、Lock Record中的Owner指针指向Mark word;(CAS操作)
升级
继续执行,且锁状态变为00(轻量级锁),markWord中偏向锁线程ID置空,升级为轻量锁。
设置monitor的各个字段:_header、_owner和_object等,并返回
开始
轻量锁获取阶段
挂起线程A
已膨胀
是否为null
线程B
通过omAlloc方法,获取一个可用的ObjectMonitor monitor,并重置monitor数据;
判断当前锁对象的对象头中MarkWord的偏向锁标志位是否为0;锁标志位是否为01(无锁);且p偏向锁线程ID是否为null/自己。(MarkOop)
失败(循环等待)
线程A
将Mark Word设置为markOopDesc:INFLATING,标识当前锁正在膨胀中,设置monitor的header字段为displaced mark word,owner字段为Lock Record,obj字段为锁对象。
0 条评论
下一页