线程第一次拿到偏向锁,仍然是通过CAS操作拿到的?

来源:9-3 synchronized底层实现原理-2

慕哥6062902

2020-05-23

老师好,最后一分钟讲到偏向锁的优点,说加锁和解锁不需要执行CAS操作,我从其它地方了解的是说,比如第一次的时候A线程通过CAS操作拿到锁的,后面A线程重进入的时候,就不需要再次进行CAS操作了,这个时候确实是没有消耗的。想请教下到底是怎样的呢

写回答

1回答

翔仔

2020-05-24

同学好,第一次还是通过CAS操作拿到锁的,但是由于此时没有别的线程占用,属于第一次,基本就不没有消耗,而重入的时候,就是不需要作CAS操作

// code 3:如果锁对象的mark word的状态是偏向模式
    if (mark->has_bias_pattern()) {      uintptr_t thread_ident;      uintptr_t anticipated_bias_locking_value;
      thread_ident = (uintptr_t)istate->thread();     // code 4:这里有几步操作,下文分析
      anticipated_bias_locking_value =
        (((uintptr_t)lockee->klass()->prototype_header() | thread_ident) ^ (uintptr_t)mark) &
        ~((uintptr_t) markOopDesc::age_mask_in_place);	 // code 5:如果偏向的线程是自己且epoch等于class的epoch
      if  (anticipated_bias_locking_value == 0) {        // already biased towards this thread, nothing to do
        if (PrintBiasedLockingStatistics) {
          (* BiasedLocking::biased_lock_entry_count_addr())++;
        }
        success = true;
      }       // code 6:如果偏向模式关闭,则尝试撤销偏向锁
      else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) {
        markOop header = lockee->klass()->prototype_header();        if (hash != markOopDesc::no_hash) {
          header = header->copy_set_hash(hash);
        }        // 利用CAS操作将mark word替换为class中的mark word
        if (Atomic::cmpxchg_ptr(header, lockee->mark_addr(), mark) == mark) {          if (PrintBiasedLockingStatistics)
            (*BiasedLocking::revoked_lock_entry_count_addr())++;
        }
      }         // code 7:如果epoch不等于class中的epoch,则尝试重偏向
      else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) {        // 构造一个偏向当前线程的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);
        }        // CAS替换对象头的mark word  
        if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), mark) == mark) {          if (PrintBiasedLockingStatistics)
            (* BiasedLocking::rebiased_lock_entry_count_addr())++;
        }        else {          // 重偏向失败,代表存在多线程竞争,则调用monitorenter方法进行锁升级
          CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
        }
        success = true;
      }      else {         // 走到这里说明当前要么偏向别的线程,要么是匿名偏向(即没有偏向任何线程)
       	// code 8:下面构建一个匿名偏向的mark word,尝试用CAS指令替换掉锁对象的mark word
        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 (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), header) == header) {           // CAS修改成功
          if (PrintBiasedLockingStatistics)
            (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++;
        }        else {          // 如果修改失败说明存在多线程竞争,所以进入monitorenter方法
          CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
        }
        success = true;
      }


1
3
翔仔
回复
Meteor流星
是的,前后有点矛盾了,以这个源码为准,不然理解上容易有偏差
2021-12-07
共3条回复

剑指Java面试-Offer直通车 百度资深面试官授课

招聘季即将到来,让百度资深面试官来为你的高薪Offer保驾护航

8427 学习 · 1870 问题

查看课程