锁的膨胀过程2
重偏向不同于锁重入
- 重偏向是第一次偏向锁已经释放了,再一次加偏向锁,就是一个代码块里有两个相邻的synchronized块
- 锁重入就是synchronized里面再套一个synchronized
一个线程进入synchronized并退出后对象头的变化
- 轻量锁加锁有个前置的逻辑
- 首先第一个线程获取锁成功后,对象头改为:线程id+101
- 当这个线程执行完退出synchronized块后,对象头改为:000…0001
synchronized源码分析
-
并发编程5中用到的openjdk源码是jdk8,其中有很多cas操作,比如轻量锁替换lock record的操作—Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced)
-
下面的代码是jdk12,对很多cas操作进行了进一步封装,更加看得懂
-
比如上面轻量锁替换锁记录的操作被更新成—lockee->cas_set_mark((markOop)entry, displaced)
-
CASE(_monitorenter): { oop lockee = STACK_OBJECT(-1); // derefing's lockee ought to provoke implicit null check CHECK_NULL(lockee); // find a free monitor or one already allocated for this object // if we find a matching object then we need a new monitor // since this is recursive enter BasicObjectLock* limit = istate->monitor_base(); BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base(); BasicObjectLock* entry = NULL; while (most_recent != limit ) { if (most_recent->obj() == NULL) entry = most_recent; else if (most_recent->obj() == lockee) break; most_recent++; } if (entry != NULL) { // entry是每个线程私有栈帧中都会创建的 // entry表示lock record // 将lock record里面的obj reference指向mark word entry->set_obj(lockee); int success = false; uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place; markOop mark = lockee->mark(); intptr_t hash = (intptr_t) markOopDesc::no_hash; // implies UseBiasedLocking // 是否支持偏向锁 if (mark->has_bias_pattern()) { uintptr_t thread_ident; uintptr_t anticipated_bias_locking_value; // 获取当前线程的id thread_ident = (uintptr_t)istate->thread(); // 这个计算比较复杂 // 如果这个值等于0,说明当前线程id和mark word里面存的线程id是相同的 anticipated_bias_locking_value = (((uintptr_t)lockee->klass()->prototype_header() | thread_ident) ^ (uintptr_t)mark) & ~((uintptr_t) markOopDesc::age_mask_in_place); // 同一个线程获取偏向锁 if (anticipated_bias_locking_value == 0) { // already biased towards this thread, nothing to do // 进入次数加1 if (PrintBiasedLockingStatistics) { (* BiasedLocking::biased_lock_entry_count_addr())++; } success = true; } // 是否不可偏向 else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) { // try revoke bias markOop header = lockee->klass()->prototype_header(); if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } if (lockee->cas_set_mark(header, mark) == mark) { if (PrintBiasedLockingStatistics) (*BiasedLocking::revoked_lock_entry_count_addr())++; } } // 是否过期,如果过期需要重偏向 else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) { // try rebias markOop new_header = (markOop) ( (intptr_t) lockee->klass()->prototype_header() | thread_ident); if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } // 就是对象头被别人改了 if (lockee->cas_set_mark(new_header, mark) == mark) { if (PrintBiasedLockingStatistics) (* BiasedLocking::rebiased_lock_entry_count_addr())++; } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } success = true; } // 进到else // 1.匿名偏向(必须是101的状态) 2. // 首先肯定不是自己 // 不是自己有两种情况 1.压根没有偏向 2. else { // try to bias towards thread in case object is anonymously biased markOop header = (markOop) ((uintptr_t) mark & ((uintptr_t)markOopDesc::biased_lock_mask_in_place | (uintptr_t)markOopDesc::age_mask_in_place | epoch_mask_in_place)); if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } markOop new_header = (markOop) ((uintptr_t) header | thread_ident); // debugging hint // 看看是否是匿名偏向 如果是则偏向自己 DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) if (lockee->cas_set_mark(new_header, header) == header) { if (PrintBiasedLockingStatistics) (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; } else { // monitorenter 首先会去进行偏向锁撤销 撤销的时候判断是否在同步块中;如果在则改成轻量锁,否则返回 CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } success = true; } } // traditional lightweight locking if (!success) { // 压根就不是偏向锁 偏向失败 // 生成一个无锁的mark word 001 markOop displaced = lockee->mark()->set_unlocked(); entry->lock()->set_displaced_header(displaced); // call_vm这个值永远是false bool call_vm = UseHeavyMonitors; // openjdk8----Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced 如果这整个是false,表示加锁成功 // openjdk12---lockee->cas_set_mark((markOop)entry, displaced) != displaced 如果这整个是false,表示加锁成功 // 这个cas操作是对比lockee->cas_set_mark((markOop)entry, displaced)里面的displaced和内存中mark word中的是一样吗,如果一样则更新为(markOop)entry 然后返回(markOop)entry 此时不等于displaced,所以cas更新成功,但是if逻辑体的结果是false // 如果此时对象头是无锁 则修改entry的地址 为什么失败? if (call_vm || lockee->cas_set_mark((markOop)entry, displaced) != displaced) { // Is it simple recursive case? if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { entry->lock()->set_displaced_header(NULL); } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } } } // 执行CPU下一条指令 UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } else { istate->set_msg(more_monitors); UPDATE_PC_AND_RETURN(0); // Re-execute } }
场景1:线程1获取锁,并释放锁,线程2进来加锁
-
必须清楚一点,对应头只有一个,多个线程对应对个线程私有栈,正常情况每个线程私有栈只有一个lock recod,当有锁重入情况时,同一个线程会有多个lock record
-
线程1获取锁成功,对象头改为:线程id+101
-
线程1释放锁,对象头改为:00…0001
-
线程2来加锁,偏向锁的逻辑都不会进入,success=false,进入轻量锁加锁逻辑,对象头改为:lock record的指针地址+00
场景2:t1来加锁,直接加锁成功
-
CASE(_monitorenter): { oop lockee = STACK_OBJECT(-1); // derefing's lockee ought to provoke implicit null check CHECK_NULL(lockee); // find a free monitor or one already allocated for this object // if we find a matching object then we need a new monitor // since this is recursive enter BasicObjectLock* limit = istate->monitor_base(); BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base(); BasicObjectLock* entry = NULL; while (most_recent != limit ) { if (most_recent->obj() == NULL) entry = most_recent; else if (most_recent->obj() == lockee) break; most_recent++; } if (entry != NULL) { // entry表示此处线程私有栈里新生成的lock record // 并将lock record里面的obj reference指向mark word // 此时是第一次,mark word是101 entry->set_obj(lockee); int success = false; uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place; markOop mark = lockee->mark(); intptr_t hash = (intptr_t) markOopDesc::no_hash; // implies UseBiasedLocking if (mark->has_bias_pattern()) { uintptr_t thread_ident; uintptr_t anticipated_bias_locking_value; thread_ident = (uintptr_t)istate->thread(); anticipated_bias_locking_value = (((uintptr_t)lockee->klass()->prototype_header() | thread_ident) ^ (uintptr_t)mark) & ~((uintptr_t) markOopDesc::age_mask_in_place); if (anticipated_bias_locking_value == 0) { // already biased towards this thread, nothing to do if (PrintBiasedLockingStatistics) { (* BiasedLocking::biased_lock_entry_count_addr())++; } success = true; } // 是否不可偏向 else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) { // try revoke bias markOop header = lockee->klass()->prototype_header(); if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } if (lockee->cas_set_mark(header, mark) == mark) { if (PrintBiasedLockingStatistics) (*BiasedLocking::revoked_lock_entry_count_addr())++; } } // 是否过期 else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) { // try rebias markOop new_header = (markOop) ( (intptr_t) lockee->klass()->prototype_header() | thread_ident); if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } if (lockee->cas_set_mark(new_header, mark) == mark) { if (PrintBiasedLockingStatistics) (* BiasedLocking::rebiased_lock_entry_count_addr())++; } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } success = true; } // 1.匿名偏向 // 2.偏向别人 else { // try to bias towards thread in case object is anonymously biased // 创建一个匿名偏向的header // 000....000101 markOop header = (markOop) ((uintptr_t) mark & ((uintptr_t)markOopDesc::biased_lock_mask_in_place | (uintptr_t)markOopDesc::age_mask_in_place | epoch_mask_in_place)); // 考虑是否有hash if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } // 创建一个偏向自己的mark // t1的线程id+101 markOop new_header = (markOop) ((uintptr_t) header | thread_ident); // debugging hint DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) // 匿名偏向就是无所可偏向 // 看看是否是匿名偏向 如果是则偏向自己 // 如果mark word中是匿名偏向---header,则更新为t1线程id+101---new if (lockee->cas_set_mark(new_header, header) == header) { if (PrintBiasedLockingStatistics) (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; } // 不是匿名偏向,就会失败 // monitorenter 首先回去进行偏向锁撤销,撤销的时候判断是否在同步块中,如果在则改成轻量锁,否则返回 else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } success = true; } } // traditional lightweight locking if (!success) { markOop displaced = lockee->mark()->set_unlocked(); entry->lock()->set_displaced_header(displaced); bool call_vm = UseHeavyMonitors; if (call_vm || lockee->cas_set_mark((markOop)entry, displaced) != displaced) { // Is it simple recursive case? if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { entry->lock()->set_displaced_header(NULL); } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } } } UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } else { istate->set_msg(more_monitors); UPDATE_PC_AND_RETURN(0); // Re-execute } }
匿名偏向锁
1.第一个进入锁的线程,就是匿名偏向(101)(无锁可偏向)的这种情况。
不考虑偏向关闭的情况。
1.1会进入到最后一个else里面,匿名偏向判断里面,
- 首先创建匿名偏向的header(在cpu内存里面存在一个匿名偏向),然后判断有没有哈希,
- 又创建一个newheade(偏向t1的mark),当前线程t1Id加上101,
- lockee -> cas_set_mark(new_header,header),
如果匿名偏向失败进入monitorenter
-
IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem)) #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif if (PrintBiasedLockingStatistics) { Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); } Handle h_obj(thread, elem->obj()); assert(Universe::heap()->is_in_reserved_or_null(h_obj()), "must be NULL or an object"); if (UseBiasedLocking) { // Retry fast entry if bias is revoked to avoid unnecessary inflation ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK); } else { ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK); } assert(Universe::heap()->is_in_reserved_or_null(elem->obj()), "must be NULL or an object"); #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif IRT_END
-
然后要么进入fast_enter(synchronized.cpp)
-
void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) { if (UseBiasedLocking) { if (!SafepointSynchronize::is_at_safepoint()) { // 为什么要revoke--撤销偏向锁 // 因为匿名偏向可能是偏向别人 BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD); if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) { return; } } else { assert(!attempt_rebias, "can not rebias toward VM thread"); BiasedLocking::revoke_at_safepoint(obj); } assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); } // 轻量锁加锁逻辑 slow_enter (obj, lock, THREAD) ; }
-
要么进入slow_enter
-
// ----------------------------------------------------------------------------- // Interpreter/Compiler Slow Case // This routine is used to handle interpreter/compiler slow case // We don't need to use fast path here, because it must have been // failed in the interpreter/compiler code. // 轻量锁加锁 void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) { markOop mark = obj->mark(); assert(!mark->has_bias_pattern(), "should not see bias pattern here"); // 是否是无锁 if (mark->is_neutral()) { // Anticipate successful CAS -- the ST of the displaced mark must // be visible <= the ST performed by the CAS. lock->set_displaced_header(mark); // 判断mark里面是不是00000001,如果是则cas成功,把mark word更新为lock reocrd的指针地址 if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) { TEVENT (slow_enter: release stacklock) ; return ; } // Fall through to inflate() ... } else if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) { assert(lock != mark->locker(), "must not re-lock the same lock"); assert(lock != (BasicLock*)obj->mark(), "don't relock with same BasicLock"); lock->set_displaced_header(NULL); return; } #if 0 // The following optimization isn't particularly useful. if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) { lock->set_displaced_header (NULL) ; return ; } #endif // The object header will never be displaced to this lock, // so it does not matter what the value is, except that it // must be non-zero to avoid looking like a re-entrant lock, // and must not look locked either. lock->set_displaced_header(markOopDesc::unused_mark()); // 膨胀 ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD); }
底层创建lock record命令
- entry->set_obj(lockee);创建一个lock record,并指向对象
场景:第二个线程释放锁后,第三个线程尝试获取锁
4.1 t2指第二个线程进来,并释放后,对象头里面存的是000001,因为t2是轻量锁,释放之后对象头是无锁
4.2 t2把锁释放了,线程私有栈里面是空的,t3进入加锁,t3 上面偏向的判断逻辑全部失败,直接进入if(!success)代码区域,会在内存中生成一个无锁的001对象头,把私有栈里面的header改为新的cpu里面的对象头,同时把加锁对象里面对象头的值替换成entry(锁记录,里面存的是指针),就是线程私有栈里面的指针,只占62位,最后两位就是00。
偏向锁的对象头组成
5.偏向锁已经偏向101
线程id+epo+ud+age+bl+lock
epo是一个时间标识
对于同一个线程,第一次偏向和第二次偏向哪个效率高—偏向锁性能高就高在这里
- 肯定是第二次,只用判断是不是同一个线程,如果是,就直接成功了,
- 如果是第一次,还有匿名偏向加锁的流程要判断
匿名偏向什么时候会失败
- t1和t2同时来第一次加锁,有一个必定会失败,因为此时mark word中的值已经被修改成加锁成功的线程id+101,另外一个线程必然会失败
判断匿名偏向锁释放过期
-
// 是否过期 else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) { // try rebias markOop new_header = (markOop) ( (intptr_t) lockee->klass()->prototype_header() | thread_ident); if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } if (lockee->cas_set_mark(new_header, mark) == mark) { if (PrintBiasedLockingStatistics) (* BiasedLocking::rebiased_lock_entry_count_addr())++; } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } success = true; }
批量重偏向的优化
-
public static void main(String[] args) throws InterruptedException { //101 可偏向 没有线程偏向 //a 没有线程偏向---匿名 101偏向锁 List<A> list = new ArrayList<>(); t1 = new Thread(){ @Override public void run() { for(int i=0;i<19;i++){ A a = new A(); list.add(a); synchronized (a){ log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } } log.debug("========================="); LockSupport.unpark(t2); } };
-
这里打印的20次,结果应该都是偏向锁
-
偏向锁过期涉及到批量撤销,当偏向锁撤销到一定次数,就会引发批量重偏向
-
public static void main(String[] args) throws InterruptedException { //101 可偏向 没有线程偏向 //a 没有线程偏向---匿名 101偏向锁 List<A> list = new ArrayList<>(); t2 = new Thread(){ @Override public void run() { for(int i=0;i<loopFlag;i++){ // 19不同的A对象 A a = new A(); list.add(a); synchronized (a){ log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } } log.debug("========================="); // 叫醒t3 LockSupport.unpark(t3=); } }; t3 = new Thread(){ @Override public void run() { // 等待t2执行完了叫醒再执行 LockSupport.park(); for (int i = 0; i <19 ; i++) { A a = list.get(i); log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); synchronized (a){ log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } } }; t2.start(); t3.start(); }
-
t3中首先是偏向锁00000101,然后撤销升级为轻量锁11110000,最后释放锁变为无锁00000001
-
但是发生了大量的偏向锁撤销,注意对同一个类的偏向锁撤销超过20次后,将上面的20改成30,会发生什么?
- jvm中如果对A这个类进行了超过20次偏向锁撤销,会进行批量重偏向
- 当超过20次后,所以A类的对象全都偏向给t3,三次都00000101
- 这种表现出的结果就像是锁降级
-
public static void main(String[] args) throws InterruptedException { //101 可偏向 没有线程偏向 //a 没有线程偏向---匿名 101偏向锁 List<A> list = new ArrayList<>(); t2 = new Thread(){ @Override public void run() { for(int i=0;i<loopFlag;i++){ // 19不同的A对象 A a = new A(); list.add(a); synchronized (a){ log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } } log.debug("========================="); // 叫醒t3 LockSupport.unpark(t3=); } }; t3 = new Thread(){ @Override public void run() { // 等待t2执行完了叫醒再执行 LockSupport.park(); for (int i = 0; i <19 ; i++) { A a = list.get(i); log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); synchronized (a){ log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } } }; t2.start(); t3.start(); t3.join(); log.debug(ClassLayout.parseInstance(new A()).toPrintable()); }
-
最后打印的new A(),是00000101,已经是批量重偏向的结果
-
但是如果把for循环的次数改成10次,打印的结果,也是00000101,但是这是默认的无锁可偏向的结果
-
static Thread t2; static Thread t3; static Thread t4; static int loopFlag=38; public static void main(String[] args) throws InterruptedException { //101 可偏向 没有线程偏向 //a 没有线程偏向---匿名 101偏向锁 List<A> list = new ArrayList<>(); t2 = new Thread(){ @Override public void run() { for(int i=0;i<50;i++){ A a = new A(); list.add(a); synchronized (a){ log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } } log.debug("========================="); LockSupport.unpark(t3); } }; t3 = new Thread(){ @Override public void run() { LockSupport.park(); for (int i = 0; i <50 ; i++) { A a = list.get(i); log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); synchronized (a){ log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } log.debug("======t3====================================="); LockSupport.unpark(t4); } }; t4 = new Thread(){ @Override public void run() { LockSupport.park(); for (int i = 0; i <50 ; i++) { A a = list.get(i); log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); synchronized (a){ log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } log.debug(i+" "+ClassLayout.parseInstance(a).toPrintableTest(a)); } } }; t2.start(); t3.start(); t4.start(); t4.join(); log.debug(ClassLayout.parseInstance(new A()).toPrintable()); }
-
如果对某个类的偏向锁撤销达到40次,此时执行最后的log.debu打印出的结果是00000001
-
这是jvm中的又一个阈值,如果对同一个类偏向撤销超过40次,此时会禁用偏向锁,也就是无锁不可偏向状态
总结
- t1来加锁,50次加锁 类的不同对象,有50个A,全都是偏向锁,偏向t1
- t2来加锁,前20个是轻量锁,也就是进行了20次偏向锁撤销(先是偏向锁,然后撤销偏向锁,再变成轻量锁),剩下30个全部都是偏向锁(批量重偏向),偏向t2,此时总共进行了20次偏向锁撤销
- t3来加锁,前20个直接是轻量锁(因为上一步轻量锁撤销后是001,即不可偏向,是直接变成轻量锁),所以没有偏向锁撤销,剩下的30个都是偏向t2,又是轻量锁撤销,当撤销达到40次后,剩下的10个就不会一个一个的撤销了,会禁用偏向锁,不管这个类的任何对象都是不可偏向的
在类当中存有对象头的数据—偏向锁过期问题
-
class类模板存在元空间中,对象头的数据存在类模板中,对应于偏向锁,其中有一个epo值(两位)
-
epo值是一个类被装载到元空间中就会存在了,如果发生批量重偏向后,epo值就会加一
-
// 是否过期 如果过期则需要重偏向--- t2 第20次加锁 else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) { // try rebias // 生成一个偏向当前线程的mark word markOop new_header = (markOop) ( (intptr_t) lockee->klass()->prototype_header() | thread_ident); if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } // 就是对象头被别人改了 // mark是这个线程记录的,如果没被别人改,肯定是可以成功的 if (lockee->cas_set_mark(new_header, mark) == mark) { if (PrintBiasedLockingStatistics) (* BiasedLocking::rebiased_lock_entry_count_addr())++; } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } success = true; }
轻量锁的重入—000
-
synchronized(this){ synchronized(this) }
-
// traditional lightweight locking if (!success) { markOop displaced = lockee->mark()->set_unlocked(); entry->lock()->set_displaced_header(displaced); bool call_vm = UseHeavyMonitors; if (call_vm || lockee->cas_set_mark((markOop)entry, displaced) != displaced) { // Is it simple recursive case? // 轻量锁的重入 if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { // 在当前线程的私有线程栈里创造一条null的lock record entry->lock()->set_displaced_header(NULL); } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } } } UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } else { istate->set_msg(more_monitors); UPDATE_PC_AND_RETURN(0); // Re-execute } }