标签:ptr line image syn 设置 obj c++ volatil src
当一个线程A执行字节码时遇到monitorenter指令时,会首先检查该指令关联的Object的对象头中的Mark Word状态。
如果2bit标志位为01代表此时处于偏向锁状态。
如果2bit标志位为01且1bit的标志位为1,代表该对象此时处于偏向锁且锁被获取状态。
如果2bit标志位为01且1bit的标志位为0,代表该对象处于偏向锁未被获取的状态,
那么执行CAS操作修改ThreadID。如果此时失败了呢?书上没说,我猜测是如果CAS操作失败那么一定是还有另一个线程此时也在CAS操作修改ThreadID。此时应该也要膨胀到轻量锁。
这里不同的资料给出了不同的解释,即关于什么时候一个线程会请求一个轻量级的锁。https://www.jianshu.com/p/c5058b6fe8e5我比较认同这里的看法,当mark word的标志位是001时,即当前无锁状态且不允许使用偏向锁的时候,就会请求使用轻量级锁。这一点和那副著名的图有所区别。
当试图获得一个轻量级锁的时候,1、首先在当前线程的栈帧中分配一个Lock Record记录,并把MarkWord复制到当前的LockRecord中 2、尝试使用CAS操作去把对象头的mark word改成指向当前LockRecord的指针
inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value) { return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value); }
上面这段c++就是获取偏向锁的过程,重点关注红色框里的CAS操作。下面就CAS方法的签名,可以看到第一个参数是要改变的值,最后一个参数是用来比较的值。所以综上可以看到获取轻量级锁的本质就是拿自己LockRecord里的markeord和此时此刻对象头的markWord比较并执行cas操作,成功了,当前线程就获得了轻量级锁。
那如果失败了呢?我虽然不太能看懂这段c++,但是我能看懂if逻辑。如果失败了的话,会把当前线程栈帧的lockRecord里的markword替换成一个名为unused_mark的东西(这东西是啥?),然后剩下的就是进入了inflate膨胀成重量级锁的阶段了。这和书上不一样啊,不是自旋吗?????
书还能错了???
上面是轻量级锁的释放逻辑,取出LockRecord里的markword记录,用cas操作把对象头里markword换回去,成功了就释放了轻量级锁,如果失败了就inflate成重量级锁。
仔细看一下这个cas操作,第一个参数是dhw,dhw就是lockrecord里存储的加锁的时候锁对象的mark,也就是说dhw是我想写回的数据。cas里第三个参数是mark,往上看发现mark是object->mark取出来的,也就是我先从锁对象里取出了mark的值,然后把取出的mark的值作为cas操作compare的值。,所以理论上这个cas操作一定是会成功的,如果失败了,说明在从取出mark到使用mark执行cas操作之间对象的mark被别人替换了。什么情况下会被替换呢?再取出mark的时候,mark已经在轻量级锁获取的时候被替换成了指向lockrecord的指针,所以markWord不会因为别的线程尝试获取轻量级锁被替换成指向别的线程lockrecord的指针。所以我猜测,maekword被替换是由于别的线程视图获取轻量级锁,发生了锁竞争,进一步锁膨胀成重量级索,在膨胀的时候markword被更改,不是指向lockrecord的指针。
结合轻量级锁的获取和竞争可以看到,轻量级锁的膨胀有可能是两个地方发生,假设A线程获得了轻量级锁,然后B线程也想获得锁,那么在B线程试图获取轻量级锁的时候,会走到inflate这段逻辑里,所以此时锁膨胀成了重量级锁。然后在A线程释放锁的时候,发现释放锁的CAS操作失败,因为markword不是指向自己lockrecord的指针了,此时A线程也会走inflate的锁膨胀逻辑。
标签:ptr line image syn 设置 obj c++ volatil src
原文地址:https://www.cnblogs.com/AshOfTime/p/10422107.html