深入浅出synchronized的原理与源码

深入浅出synchronized的原理与源码

1.java对象头关于锁的标识

1.对象头

//  32 bits:
//  --------
//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
//             size:32 ------------------------------------------>| (CMS free block)
//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
//  64 bits:
//  --------
//  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
//  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
//  size:64 ----------------------------------------------------->| (CMS free block)
//
//  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
//  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
//  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
//  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)

//    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
//    [0           | epoch | age | 1 | 01]       lock is anonymously biased
//
//  - the two lock bits are used to describe three states: locked/unlocked and monitor.
//
//    [ptr             | 00]  locked             ptr points to real header on stack
//    [header      | 0 | 01]  unlocked           regular object header
//    [ptr             | 10]  monitor            inflated lock (header is wapped out)
//    [ptr             | 11]  marked             used by markSweep to mark an object
//                                               not valid at any other time

2.java中synchronized的字节码表示

在java中使用synchronized会在字节码层面生成monitorenter和_monitorexit。这是一个上锁和解锁的过程保证原子性的操作。

3.monitorenter的流程图

4.moniterexit的流程图

2.JVM源码

bytecodeInterpreter.cpp中的_monitorenter

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;//如果当前的锁对象时lockee直接返回
          most_recent++;
        }
        if (entry != NULL) {//entry不为空表示有BasicObjectLock,有锁对象可以获取
          entry->set_obj(lockee);//设置当前锁对象为lockee
          int success = false;
          uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place;//获取epoch的值

          markOop mark = lockee->mark();//获取锁对象头部
          intptr_t hash = (intptr_t) markOopDesc::no_hash;//获取原始的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);// 获取原始对象头部 组合 上当前线程地址信息,与当前对象做对比(异或运算,相同为 0,相异为 1,运算后保留为 1 的位也即不同位),随后 与 对象年龄位的相反值做与运算(与运算等价于二进制截断,混沌学堂中说过哈),等价于 :将当前对象头部相对于原始对象头部不同的位,去掉年龄位,得到anticipated_bias_locking_value 

            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) {//如果hash值不同
                header = header->copy_set_hash(hash);//头部设置hash值
              }
              if (lockee->cas_set_mark(header, mark) == mark) {//cas将当前锁的头部替换为原型头部,也即尝试撤销偏向锁
                if (PrintBiasedLockingStatistics)
                  (*BiasedLocking::revoked_lock_entry_count_addr())++;
              }
            }
            else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) {//如果当前头部已经发生变化,并且epoch不为0,表示已经滚动过,尝试重偏向。这里表示发生过批量锁撤销
              // try rebias
              markOop new_header = (markOop) ( (intptr_t) lockee->klass()->prototype_header() | thread_ident);//获取到当前线程的原型头部
              if (hash != markOopDesc::no_hash) {//hash值不同设置hash值
                new_header = new_header->copy_set_hash(hash);
              }
              if (lockee->cas_set_mark(new_header, mark) == mark) {//cas将当前头部替换为新头部,也即尝试冲片向
                if (PrintBiasedLockingStatistics)
                  (* BiasedLocking::rebiased_lock_entry_count_addr())++;
              }
              else {//cas失败,进入monitorenter.
                CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
              }
              success = true;
            }
            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));//// 因为 匿名偏向锁 中保存着 当前对象头的头部信息(年龄、epoch)所以需要保留下来
              
                if (hash != markOopDesc::no_hash) {///hash值不同设置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) {//cas将头部替换为new_header,偏向当前线程
                if (PrintBiasedLockingStatistics)
                  (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++;
              }
              else {//cas失败进入monitorenter
                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;//默认是false
            if (call_vm || lockee->cas_set_mark((markOop)entry, displaced) != displaced) {//cas将当前头部替换为entry,也即轻量级锁
              // Is it simple recursive case?
              if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) {//判断当前线程是否就是上锁的线程
                entry->lock()->set_displaced_header(NULL);//锁重入,将当前lock的头部置为空
              } else {//否则头部替换失败,进入monitorenter
                CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
              }
            }
          }
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
        } else {
          istate->set_msg(more_monitors);//当前没有锁对象,set_msg,提示需要更多的监视器对象
          UPDATE_PC_AND_RETURN(0); // Re-execute
        }
      }

InterpreterRuntime::monitorenter

IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem))
  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 {//否则直接执行slow_enter锁升级
    ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
  }
IRT_END

ObjectSynchronizer::fast_enter

void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock,
                                    bool attempt_rebias, TRAPS) {
  if (UseBiasedLocking) {//如果拥有偏向锁
    if (!SafepointSynchronize::is_at_safepoint()) {//是否在线程安全点。线程安全点的时候,所有在安全点的线程会进行等待。
      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);//进入锁升级过程
}

BiasedLocking::revoke_and_rebias

BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {
  // We can revoke the biases of anonymously-biased objects
  // efficiently enough that we should not cause these revocations to
  // update the heuristics because doing so may cause unwanted bulk
  // revocations (which are expensive) to occur.
  markOop mark = obj->mark();//获取当前头部
  if (mark->is_biased_anonymously() && !attempt_rebias) {//如果头部是匿名偏向锁,并且不允许重偏向
    // We are probably trying to revoke the bias of this object due to
    // an identity hash code computation. Try to revoke the bias
    // without a safepoint. This is possible if we can successfully
    // compare-and-exchange an unbiased header into the mark word of
    // the object, meaning that no other thread has raced to acquire
    // the bias of the object.
    markOop biased_value       = mark;
    markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());//获取没有偏向锁的原型头部
    markOop res_mark = obj->cas_set_mark(unbiased_prototype, mark);//cas设置mark头部的值
    if (res_mark == biased_value) {//cas成功,标识锁撤销
      return BIAS_REVOKED;//返回BIAS_REVOKED
    }
  } else if (mark->has_bias_pattern()) {//如果当前是偏向锁
    Klass* k = obj->klass();//获取原始类对象
    markOop prototype_header = k->prototype_header();//获取原始头部
    if (!prototype_header->has_bias_pattern()) {//如果原始头部无偏向锁
      // This object has a stale bias from before the bulk revocation
      // for this data type occurred. It's pointless to update the
      // heuristics at this point so simply update the header with a
      // CAS. If we fail this race, the object's bias has been revoked
      // by another thread so we simply return and let the caller deal
      // with it.
      markOop biased_value       = mark;
      markOop res_mark = obj->cas_set_mark(prototype_header, mark);//cas替换头部,撤销偏向锁
      assert(!obj->mark()->has_bias_pattern(), "even if we raced, should still be revoked");
      return BIAS_REVOKED;//返回BIAS_REVOKED
    } else if (prototype_header->bias_epoch() != mark->bias_epoch()) {//如果原始头部的epoch与当前头部的epoch不同,表示滚动或当前轮次。
      // The epoch of this biasing has expired indicating that the
      // object is effectively unbiased. Depending on whether we need
      // to rebias or revoke the bias of this object we can do it
      // efficiently enough with a CAS that we shouldn't update the
      // heuristics. This is normally done in the assembly code but we
      // can reach this point due to various points in the runtime
      // needing to revoke biases.
      if (attempt_rebias) {//是否允许重偏向
        assert(THREAD->is_Java_thread(), "");
        markOop biased_value       = mark;
        markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch());//重偏向头部组装
        markOop res_mark = obj->cas_set_mark(rebiased_prototype, mark);//cas设置mark值,成功表示重偏向成功
        if (res_mark == biased_value) {//相等,表示撤销重偏向成功
          return BIAS_REVOKED_AND_REBIASED;//返回:BIAS_REVOKED_AND_REBIASED
        }
      } else {//不允许重偏向,直接撤销偏向锁
        markOop biased_value       = mark;
        markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
        markOop res_mark = obj->cas_set_mark(unbiased_prototype, mark);
        if (res_mark == biased_value) {
          return BIAS_REVOKED;
        }
      }
    }
  }

BiasedLocking::revoke_at_safepoint

void BiasedLocking::revoke_at_safepoint(Handle h_obj) {
  oop obj = h_obj();
  HeuristicsResult heuristics = update_heuristics(obj, false);
  if (heuristics == HR_SINGLE_REVOKE) {//如果是HR_SINGLE_REVOKE,表示单个偏向锁撤销
    revoke_bias(obj, false, false, NULL, NULL);
  } else if ((heuristics == HR_BULK_REBIAS) ||
             (heuristics == HR_BULK_REVOKE)) {//HR_BULK_REBIAS,HR_BULK_REVOKE表示批量的操作。
    bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL);//批量的操作需要在线程安全点,进行批量操作
  }
  clean_up_cached_monitor_info();//清楚缓存的监视器信息
}

HeuristicsResult::update_heuristics

static HeuristicsResult update_heuristics(oop o, bool allow_rebias) {
  markOop mark = o->mark();//获取头部mark
  if (!mark->has_bias_pattern()) {//如果不是偏向锁直接返回
    return HR_NOT_BIASED;
  }

  // Heuristics to attempt to throttle the number of revocations.
  // Stages:
  // 1. Revoke the biases of all objects in the heap of this type,
  //    but allow rebiasing of those objects if unlocked.
  // 2. Revoke the biases of all objects in the heap of this type
  //    and don't allow rebiasing of these objects. Disable
  //    allocation of objects of that type with the bias bit set.
  Klass* k = o->klass();//获取类元数据对象
  jlong cur_time = os::javaTimeMillis();
  jlong last_bulk_revocation_time = k->last_biased_lock_bulk_revocation_time();//获取上一次批量撤销的时间
  int revocation_count = k->biased_lock_revocation_count();//获取偏向锁撤销的次数
  if ((revocation_count >= BiasedLockingBulkRebiasThreshold) &&//撤销的次数大于批量重偏向的阈值 BiasedLockingBulkRebiasThreshold, 20
      (revocation_count <  BiasedLockingBulkRevokeThreshold) &&//撤销的次数小于于批量撤销的阈值 BiasedLockingBulkRevokeThreshold, 40
      (last_bulk_revocation_time != 0) &&//上一次批量撤销的时间不为0
      (cur_time - last_bulk_revocation_time >= BiasedLockingDecayTime)) {//当前时间-上一次批量撤销的时间是否大于BiasedLockingDecayTime, 25000。大于这个时间,标识当前这个批量撤销,已经腐朽无效了,直接重置
    // This is the first revocation we've seen in a while of an
    // object of this type since the last time we performed a bulk
    // rebiasing operation. The application is allocating objects in
    // bulk which are biased toward a thread and then handing them
    // off to another thread. We can cope with this allocation
    // pattern via the bulk rebiasing mechanism so we reset the
    // klass's revocation count rather than allow it to increase
    // monotonically. If we see the need to perform another bulk
    // rebias operation later, we will, and if subsequently we see
    // many more revocation operations in a short period of time we
    // will completely disable biasing for this type.
    k->set_biased_lock_revocation_count(0);//将偏向锁撤销次数置为0
    revocation_count = 0;
  }

  // Make revocation count saturate just beyond BiasedLockingBulkRevokeThreshold
  if (revocation_count <= BiasedLockingBulkRevokeThreshold) {//如果撤销的次数小于等于批量锁撤销的阈值
    revocation_count = k->atomic_incr_biased_lock_revocation_count();//增加锁撤销的次数
  }

  if (revocation_count == BiasedLockingBulkRevokeThreshold) {//如果撤销的次数等于批量锁撤销的阈值
    return HR_BULK_REVOKE;//返回HR_BULK_REVOKE,表示批量锁撤销
  }

  if (revocation_count == BiasedLockingBulkRebiasThreshold) {//如果撤销的次数等于批量重偏向的阈值
    return HR_BULK_REBIAS;//HR_BULK_REBIAS,表示批量重偏向
  }

  return HR_SINGLE_REVOKE;//否则返回HR_SINGLE_REVOKE,表示只撤销单个
}

bulk_revoke_or_rebias_at_safepoint

static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,
                                                                   bool bulk_rebias,
                                                                   bool attempt_rebias_of_object,
                                                                   JavaThread* requesting_thread) {
  jlong cur_time = os::javaTimeMillis();//获取当前时间
  o->klass()->set_last_biased_lock_bulk_revocation_time(cur_time);//设置批量锁操作的时间


  Klass* k_o = o->klass();//获取类的元数据信息
  Klass* klass = k_o;

  {
    JavaThreadIteratorWithHandle jtiwh;

    if (bulk_rebias) {//如果是批量重偏向
      if (klass->prototype_header()->has_bias_pattern()) {//判断当前原型头部是否有偏向锁位
        int prev_epoch = klass->prototype_header()->bias_epoch();//获取当前偏向锁的轮次
        klass->set_prototype_header(klass->prototype_header()->incr_bias_epoch());//增加偏向锁的轮次
        int cur_epoch = klass->prototype_header()->bias_epoch();

        // Now walk all threads' stacks and adjust epochs of any biased
        // and locked objects of this data type we encounter
        for (; JavaThread *thr = jtiwh.next(); ) {
          GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);//获取当前线程栈的锁信息
          for (int i = 0; i < cached_monitor_info->length(); i++) {//遍历线程栈的锁信息
            MonitorInfo* mon_info = cached_monitor_info->at(i);
            oop owner = mon_info->owner();
            markOop mark = owner->mark();
            if ((owner->klass() == k_o) && mark->has_bias_pattern()) {//如果锁对象等于k_0对象并且有偏向锁
              // We might have encountered this object already in the case of recursive locking
              owner->set_mark(mark->set_bias_epoch(cur_epoch));//设置头部的epoch轮次
            }
          }
        }
      }

      // At this point we're done. All we have to do is potentially
      // adjust the header of the given object to revoke its bias.
      revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread, NULL);//撤销偏向锁
    } else {//否则不是批量重偏向
      if (log_is_enabled(Info, biasedlocking)) {
        ResourceMark rm;
        log_info(biasedlocking)("* Disabling biased locking for type %s", klass->external_name());
      }

      // Disable biased locking for this data type. Not only will this
      // cause future instances to not be biased, but existing biased
      // instances will notice that this implicitly caused their biases
      // to be revoked.
      klass->set_prototype_header(markOopDesc::prototype());//设置原型头部。所有的对象都依赖于一个元数据类,所以只需要设置原型头部

      // Now walk all threads' stacks and forcibly revoke the biases of
      // any locked and biased objects of this data type we encounter.
      for (; JavaThread *thr = jtiwh.next(); ) {
        GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
        for (int i = 0; i < cached_monitor_info->length(); i++) {
          MonitorInfo* mon_info = cached_monitor_info->at(i);
          oop owner = mon_info->owner();
          markOop mark = owner->mark();
          if ((owner->klass() == k_o) && mark->has_bias_pattern()) {//当前监视器的拥有者对象等于k_o,并且有偏向锁
            revoke_bias(owner, false, true, requesting_thread, NULL);//批量锁撤销
          }
        }
      }

      // Must force the bias of the passed object to be forcibly revoked
      // as well to ensure guarantees to callers
      revoke_bias(o, false, true, requesting_thread, NULL);//批量锁撤销或者锁撤销
    }
  } // ThreadsListHandle is destroyed here.

  BiasedLocking::Condition status_code = BiasedLocking::BIAS_REVOKED;

  if (attempt_rebias_of_object &&//如果允许重偏向,重偏向到requesting_thread线程
      o->mark()->has_bias_pattern() &&//mark头部标识有锁
      klass->prototype_header()->has_bias_pattern()) {//原型头部也标识有锁
    markOop new_mark = markOopDesc::encode(requesting_thread, o->mark()->age(),
                                           klass->prototype_header()->bias_epoch());//重组头部
    o->set_mark(new_mark);//设置对象头部
    status_code = BiasedLocking::BIAS_REVOKED_AND_REBIASED;//设置状态信息
    log_info(biasedlocking)("  Rebiased object toward thread " INTPTR_FORMAT, (intptr_t) requesting_thread);
  }
  return status_code;//返回状态信息
}

BiasedLocking::Condition revoke_bias


// After the call, *biased_locker will be set to obj->mark()->biased_locker() if biased_locker != NULL,
// AND it is a living thread. Otherwise it will not be updated, (i.e. the caller is responsible for initialization).
static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread, JavaThread** biased_locker) {
  markOop mark = obj->mark();//获取对象mark头部
  if (!mark->has_bias_pattern()) {//没有头部直接返回
    return BiasedLocking::NOT_BIASED;
  }

  uint age = mark->age();//获取年龄待
  markOop   biased_prototype = markOopDesc::biased_locking_prototype()->set_age(age);//设置有偏向锁的原型头部年龄
  markOop unbiased_prototype = markOopDesc::prototype()->set_age(age);//设置没有偏向锁的原型头部年龄

  JavaThread* biased_thread = mark->biased_locker();//获取持有偏向锁的线程
  if (biased_thread == NULL) {//线程为空
    // Object is anonymously biased. We can get here if, for
    // example, we revoke the bias due to an identity hash code
    // being computed for an object.
    if (!allow_rebias) {//判断允许重偏向
      obj->set_mark(unbiased_prototype);//设置mark头部为没有偏向锁的头部
    }
    return BiasedLocking::BIAS_REVOKED;//返回偏向锁撤销
  }

  // Handle case where the thread toward which the object was biased has exited
  bool thread_is_alive = false;//线程是否存活标识
  if (requesting_thread == biased_thread) {//requesting_thread线程是偏向锁线程
    thread_is_alive = true;
  } else {
    ThreadsListHandle tlh;
    thread_is_alive = tlh.includes(biased_thread);//遍历判断线程是否存活
  }
  if (!thread_is_alive) {//线程已经不是存活状态
    if (allow_rebias) {//允许重偏向
      obj->set_mark(biased_prototype);//设置mark为偏向锁的原型头部
    } else {
      obj->set_mark(unbiased_prototype);//设置mark为不持有偏向锁的原型头部
    }
    return BiasedLocking::BIAS_REVOKED;//返回状态BIAS_REVOKED,表示偏向锁撤销
  }

  // Thread owning bias is alive.
  // Check to see whether it currently owns the lock and, if so,
  // write down the needed displaced headers to the thread's stack.
  // Otherwise, restore the object's header either to the unlocked
  // or unbiased state.
   //// 持有偏向锁的线程仍旧存活,那么遍历它的线程栈的锁信息(这里为 锁重入场景,因为锁重入会创建多个 BasicObjectLock 信息),将当前锁对象的 BasicLock 的替换头部信息设置为不存在偏向锁的对象头部
  GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(biased_thread);//获取所有的监视器对象
  BasicLock* highest_lock = NULL;
  for (int i = 0; i < cached_monitor_info->length(); i++) {//遍历监视器信息
    MonitorInfo* mon_info = cached_monitor_info->at(i);
    if (oopDesc::equals(mon_info->owner(), obj)) {//如果监视器对象的拥有者是obj
      // Assume recursive case and fix up highest lock later
      markOop mark = markOopDesc::encode((BasicLock*) NULL);//设置mark为null
      highest_lock = mon_info->lock();
      highest_lock->set_displaced_header(mark);//将为空的mark设置到头部中
    } else {
      log_trace(biasedlocking)("   mon_info->owner (" PTR_FORMAT ") != obj (" PTR_FORMAT ")",
                               p2i((void *) mon_info->owner()),
                               p2i((void *) obj));
    }
  }
  //// 最高位的锁为锁重入的最后一把锁,所以需要将锁替换后的头部修正为不开启偏向锁的头部,且将对象的头部还原为指向 该线程的最高位锁:BasicLock。此时,等价于将偏向锁升级为了 轻量级锁状态:对象头部的 mark 指针指向 线程栈上的 BasicObjectLock 而不是 线程 ID
  if (highest_lock != NULL) {//表示锁重入的最后一把锁
    // Fix up highest lock to contain displaced header and point
    // object at it
    highest_lock->set_displaced_header(unbiased_prototype);//将highest_lock头部设置为没有偏向锁的原型头部
    // Reset object header to point to displaced mark.
    // Must release storing the lock address for platforms without TSO
    // ordering (e.g. ppc).
    obj->release_set_mark(markOopDesc::encode(highest_lock));//将当前持有锁的ob对象的头部锁释放
  } else {
    if (allow_rebias) {//如果允许重偏向
      obj->set_mark(biased_prototype);//直接将obj设置为biased_prototype,偏向锁的原型头部
    } else {
      // Store the unlocked value into the object's header.
      obj->set_mark(unbiased_prototype);//直接将obj设置为biased_prototype,没有偏向锁的原型头部
    }
  }

  // If requested, return information on which thread held the bias
  if (biased_locker != NULL) {
    *biased_locker = biased_thread;
  }

  return BiasedLocking::BIAS_REVOKED;//返回BIAS_REVOKED
}

ObjectSynchronizer::slow_enter

void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
  markOop mark = obj->mark();//对象头部
  if (mark->is_neutral()) {//mark是否是无锁
    // Anticipate successful CAS -- the ST of the displaced mark must
    // be visible <= the ST performed by the CAS.
    lock->set_displaced_header(mark);//设置lock的头部
    if (mark == obj()->cas_set_mark((markOop) lock, mark)) {//cas将锁对象设置为lock。
      return;返回
    }
    // Fall through to inflate() ...
  } else if (mark->has_locker() &&//mark当前头部有锁
             THREAD->is_lock_owned((address)mark->locker())) {//当前线程是否是锁的拥有者
    lock->set_displaced_header(NULL);//锁重入
    return;
  }

  // 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(),
                              inflate_cause_monitor_enter)->enter(THREAD);
}

ObjectSynchronizer::inflate

ObjectMonitor* ObjectSynchronizer::inflate(Thread * Self,
                                                     oop object,
                                                     const InflateCause cause) {

  EventJavaMonitorInflate event;

  for (;;) {
    const markOop mark = object->mark();//获取对象头部
    assert(!mark->has_bias_pattern(), "invariant");

    // The mark can be in one of the following states:
    // *  Inflated     - just return
    // *  Stack-locked - coerce it to inflated
    // *  INFLATING    - busy wait for conversion to complete
    // *  Neutral      - aggressively inflate the object.
    // *  BIASED       - Illegal.  We should never see this

    // CASE: inflated
    if (mark->has_monitor()) {//如果当前mark对象已经有了monitor,也即有了重量级锁
      ObjectMonitor * inf = mark->monitor();//获得monitor对象
      return inf;//直接返回
    }
    if (mark == markOopDesc::INFLATING()) {//如果当前对象在锁膨胀过程中
      ReadStableMark(object);//读取最新头部mark
      continue;
    }

    if (mark->has_locker()) {//如果当前有锁,标识持有
      ObjectMonitor * m = omAlloc(Self);//获取一个ObjectMonitor对象
      // Optimistically prepare the objectmonitor - anticipate successful CAS
      // We do this before the CAS in order to minimize the length of time
      // in which INFLATING appears in the mark.
      m->Recycle();
      m->_Responsible  = NULL;//Reponsible的作用:优化操作当nxt==null或者_EntryList为空,标识后续没有需要等待的线程,将自身作为头结点,去睡眠一秒钟后,醒过来直接获得锁继续执行,而不是等待唤醒,提升性能。
      m->_recursions   = 0;
      m->_SpinDuration = ObjectMonitor::Knob_SpinLimit;   // Consider: maintain by type/class

      markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark);//cas将头部状态进行替换
      if (cmp != mark) {//cas失败,继续尝试
        omRelease(Self, m, true);//释放监视器对象
        continue;       // Interference -- just retry
      }
        
      //// 若执行到这里,那么当前线程负责所膨胀,只需要将对象原始的头部放置在 ObjectMonitor 中,但这里需要注意的是:由于轻量级锁仍然被其他线程所持有,所以这里 ObjectMonitor 的 owner 为 BasicObjectLock 而不是线程
      markOop dmw = mark->displaced_mark_helper();//获取轻量级锁的头部

      // Setup monitor fields to proper values -- prepare the monitor
      m->set_header(dmw);//设置头部为dmw
      m->set_owner(mark->locker());//将当前monitor拥有者设置为轻量级锁的对象
      m->set_object(object);//设置对象为object
      object->release_set_mark(markOopDesc::encode(m));//将对象头部设置为监视器头部
      return m;//返回对象
    }
	
    //对象的提前初始化
    ObjectMonitor * m = omAlloc(Self);
    // prepare m for installation - set monitor to initial state
    m->Recycle();
    m->set_header(mark);
    m->set_owner(NULL);
    m->set_object(object);
    m->_recursions   = 0;
    m->_Responsible  = NULL;
    m->_SpinDuration = ObjectMonitor::Knob_SpinLimit;       // consider: keep metastats by type/class

    if (object->cas_set_mark(markOopDesc::encode(m), mark) != mark) {//尝试cas将object的头部mark置为ObjectMonitor对象
      //cas失败,参数还原继续尝试
      m->set_object(NULL);//
      m->set_owner(NULL);
      m->Recycle();
      omRelease(Self, m, true);
      m = NULL;
      continue;
    }

    return m;//返回监视器对象m
  }
}

ObjectMonitor::enter

void ObjectMonitor::enter(TRAPS) {

  Thread * const Self = THREAD;//获取线程对象

  void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);//  CAS 尝试将当前线程设置为 owner,若设置成功,表明当前线程获取了该监视器锁。注意:该方法若成功,那么将会返回比较值 null,若失败将返回 _owner 最新值(参考并发专题的描述)
  if (cur == NULL) {// 比较成功,则返回比较值 null,说明当前线程抢到了锁,直接返回
    return;
  }

  if (cur == Self) {// 比较失败,返回当前最新值,表明当前线程锁重入,增加重入次数即可
    _recursions++;//锁重入
    return;
  }

  if (Self->is_lock_owned ((address)cur)) {// 当前线程之前已经获取到轻量级锁,然后执行业务,其他线程无法获取锁,从而将其升级到重量级锁,而当前线程在持有轻量级锁后,又重复获取锁,那么此时只需要将 重入次数和 owner修改即可
    assert(_recursions == 0, "internal state error");
    _recursions = 1;
    _owner = Self;
    return;
  }

  Self->_Stalled = intptr_t(this);// 设置当前线程阻塞在该 ObjectMonitor上


  if (TrySpin(Self) > 0) {//尝试自旋获取锁
    Self->_Stalled = 0;//获取成功置为0
    return;//返回
  }
  JavaThread * jt = (JavaThread *) Self;//获取当前线程java的线程对象
  // Prevent deflation at STW-time.  See deflate_idle_monitors() and is_busy().
  // Ensure the object-monitor relationship remains stable while there's contention.
  Atomic::inc(&_count);//引用计数加1

  JFR_ONLY(JfrConditionalFlushWithStacktrace<EventJavaMonitorEnter> flush(jt);)
  EventJavaMonitorEnter event;
  if (event.should_commit()) {
    event.set_monitorClass(((oop)this->object())->klass());
    event.set_address((uintptr_t)(this->object_addr()));
  }

  { // Change java thread status to indicate blocked on monitor enter.
    JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);

    Self->set_current_pending_monitor(this);//标识当前线程阻塞在当前objectMonitor上

    for (;;) {
     
      EnterI(THREAD);//完成获取锁的流程
      //获取成功后参数置位
      _recursions = 0;
      _succ = NULL;
      exit(false, Self);
      jt->java_suspend_self();
    }
  }

  Atomic::dec(&_count);//引用计数减1
  Self->_Stalled = 0;
}

ObjectMonitor::EnterI


void ObjectMonitor::EnterI(TRAPS) {
  Thread * const Self = THREAD;//获取当前线程对象

  // Try the lock - TATAS
  if (TryLock (Self) > 0) {//cas自旋抢锁。成功直接返回
    return;
  }

 
  if (TrySpin(Self) > 0) {//尝试自旋,中间如果抢到锁,直接返回
    return;
  }

  //参数初始化  
  ObjectWaiter node(Self);//新建等待节点
  Self->_ParkEvent->reset();//重置parkEvent
  node._prev   = (ObjectWaiter *) 0xBAD;
  node.TState  = ObjectWaiter::TS_CXQ;

  ObjectWaiter * nxt;
    //头插法,插入成功直接退出。
  for (;;) {
    node._next = nxt = _cxq;
    if (Atomic::cmpxchg(&node, &_cxq, nxt) == nxt) break;
    //尝试继续抢锁,抢到直接返回
    if (TryLock (Self) > 0) {
      return;
    }
  }

  //如果nxt = _cxq队列和_EntryList队列都为空
  if (nxt == NULL && _EntryList == NULL) {
    // Try to assume the role of responsible thread for the monitor.
    // CONSIDER:  ST vs CAS vs { if (Responsible==null) Responsible=Self }
    Atomic::replace_if_null(Self, &_Responsible);//如果_Responsible为空的话,赋值为Self
  }

  int nWakeups = 0;
  int recheckInterval = 1;

  for (;;) {

    if (TryLock(Self) > 0) break;//抢锁成功直接返回
    // park self
    if (_Responsible == Self) {//如果_Responsible是当前Self,_Responsible属于优化操作,不让线程直接取阻塞等待唤醒,而是超时等待,过了一定时间自己醒过来去获取锁
      Self->_ParkEvent->park((jlong) recheckInterval);//进行超时等待
      // Increase the recheckInterval, but clamp the value.
      recheckInterval *= 8;
      if (recheckInterval > MAX_RECHECK_INTERVAL) {//MAX_RECHECK_INTERVAL 1000
        recheckInterval = MAX_RECHECK_INTERVAL;
      }
    } else {
      Self->_ParkEvent->park();//进行阻塞等待
    }

    if (TryLock(Self) > 0) break;//获得锁,直接返回
    OM_PERFDATA_OP(FutileWakeups, inc());
    ++nWakeups;
    if (TrySpin(Self) > 0) break;//尝试自旋,获得锁直接返回

    if (_succ == Self) _succ = NULL;//获得锁了,需要将_succ置为空
    OrderAccess::fence();//全屏障,保证上述操作的变量,下面的流程都可以获取到最新值
  }

  UnlinkAfterAcquire(Self, &node);//进行断链
  if (_succ == Self) _succ = NULL;

  if (_Responsible == Self) {
    _Responsible = NULL;
    OrderAccess::fence(); // Dekker pivot-point
  }
  return;
}

ObjectMonitor::TryLock

int ObjectMonitor::TryLock(Thread * Self) {
  void * own = _owner;//获取锁的拥有者
  if (own != NULL) return 0;//如果有其他线程已经获得锁,直接返回
  if (Atomic::replace_if_null(Self, &_owner)) {//原子性操作,设置_owner为Self也即当前线程,设置成功
    // Either guarantee _recursions == 0 or set _recursions = 0.
    return 1;//返回1,表示获取锁成功
  }
  // The lock had been free momentarily, but we lost the race to the lock.
  // Interference -- the CAS failed.
  // We can either return -1 or retry.
  // Retry doesn't make as much sense because the lock was just acquired.
  return -1;
}

ObjectMonitor::TrySpin

int ObjectMonitor::TrySpin(Thread * Self) {
  int ctr = Knob_FixedSpin;//Knob_FixedSpin           = 0;
  if (ctr != 0) {//如果ctr不等于0,尝试自旋获得锁
    while (--ctr >= 0) {
      if (TryLock(Self) > 0) return 1;
      SpinPause();
    }
    return 0;
  }

  //for循环等待,并尝试获得锁
  for (ctr = Knob_PreSpin + 1; --ctr >= 0;) {// Knob_PreSpin= 10;// 20-100 likely better
    if (TryLock(Self) > 0) {//尝试获取锁
      int x = _SpinDuration;//初始值为0
      if (x < Knob_SpinLimit) {//ObjectMonitor::Knob_SpinLimit = 5000;
        if (x < Knob_Poverty) x = Knob_Poverty;//Knob_Poverty = 1000;
        _SpinDuration = x + Knob_BonusB;
      }
      return 1;
    }
    SpinPause();
  }
  //这里表示自旋过程中并没有获得锁
  ctr = _SpinDuration;
  if (ctr <= 0) return 0;
  //线程不是可执行状态
  if (NotRunnable(Self, (Thread *) _owner)) {
    return 0;
  }
  //如果当前_succ变量为空设置为Self,下次加速当前线程获得锁
  if (_succ == NULL) {
    _succ = Self;
  }
  Thread * prv = NULL;
 
  while (--ctr >= 0) {
    if ((ctr & 0xFF) == 0) {//如果ctr的低8位为0,判断是否需要阻塞
      if (SafepointMechanism::should_block(Self)) {//线程安全点机制判断是否需要阻塞
        goto Abort;           // abrupt spin egress
      }
      SpinPause();
    }

    Thread * ox = (Thread *) _owner;//获取锁对象拥有线程
    if (ox == NULL) {//如果为空表示无锁
      ox = (Thread*)Atomic::cmpxchg(Self, &_owner, (void*)NULL);//cas替换_owner为Self
      if (ox == NULL) {//表示cas成功也即获得锁
        if (_succ == Self) {
          _succ = NULL;
        }
        int x = _SpinDuration;
        if (x < Knob_SpinLimit) {
          if (x < Knob_Poverty) x = Knob_Poverty;
          _SpinDuration = x + Knob_Bonus;
        }
        return 1;//返回1
      }
      prv = ox;
      goto Abort;
    }
	
    //后续皆为简单的条件判断,不做过多赘述
    if (ox != prv && prv != NULL) {
      goto Abort;
    }
    prv = ox;
    if (NotRunnable(Self, ox)) {
      goto Abort;
    }
    if (_succ == NULL) {
      _succ = Self;
    }
  }
  {
    int x = _SpinDuration;
    if (x > 0) {
      x -= Knob_Penalty;
      if (x < 0) x = 0;
      _SpinDuration = x;
    }
  }

 Abort:
  if (_succ == Self) {//如果_succ为当前self
    _succ = NULL;//置为空
    OrderAccess::fence();//全屏障保证后续可以看到最小值
    if (TryLock(Self) > 0) return 1;//尝试获取锁,成功返回1
  }
  return 0;//返回0
}

bytecodeInterpreter.cpp中的_monitorexit

CASE(_monitorexit): {
        oop lockee = STACK_OBJECT(-1);//获取操作数栈上的锁对象
        BasicObjectLock* limit = istate->monitor_base();
        BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base();
        while (most_recent != limit ) {//遍历操作数栈上的对象找到要释放的锁对象
          if ((most_recent)->obj() == lockee) {//如果当前对象等于lockee锁对象
            BasicLock* lock = most_recent->lock();
            markOop header = lock->displaced_header();// 获取被替换后的对象头部(偏向锁不替换,这里了解即可,轻量级锁时还会回来)
            most_recent->set_obj(NULL);//将锁对象的持有者obj置为空
            if (!lockee->mark()->has_bias_pattern()) {//判断是否有偏向锁
              bool call_vm = UseHeavyMonitors;
              if (header != NULL || call_vm) {
                markOop old_header = markOopDesc::encode(lock);
                if (call_vm || lockee->cas_set_mark(header, old_header) != old_header) {//cas设置mark头部为header
                  // restore object for the slow case
                  most_recent->set_obj(lockee);//还原锁对象
                  CALL_VM(InterpreterRuntime::monitorexit(THREAD, most_recent), handle_exception);//进入monitorexit进一步释放锁
                }
              }
            }
            UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
          }
          most_recent++;
        }
        // 非正常情况,抛出对应处理异常
        CALL_VM(InterpreterRuntime::throw_illegal_monitor_state_exception(THREAD), handle_exception);
        ShouldNotReachHere();
      }

InterpreterRuntime::monitorexit

IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorexit(JavaThread* thread, BasicObjectLock* elem))
  Handle h_obj(thread, elem->obj());//获取锁对象
  
  if (elem == NULL || h_obj()->is_unlocked()) {//如果锁对象为空或者没有锁
    THROW(vmSymbols::java_lang_IllegalMonitorStateException());//抛出异常
  }
  ObjectSynchronizer::slow_exit(h_obj(), elem->lock(), thread);//进入slow_exit,慢退出,进一步解锁
  // Free entry. This must be done here, since a pending exception might be installed on
  // exit. If it is not cleared, the exception handling code will try to unlock the monitor again.
  elem->set_obj(NULL);//释放锁
IRT_END
    
void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) {
  fast_exit(object, lock, THREAD);
}

fast_exit方法


void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
  markOop mark = object->mark();//获取对象头部信息
  markOop dhw = lock->displaced_header();//获取锁对象的头部
  if (dhw == NULL) {//如果锁对象头部为空
#ifndef PRODUCT
    if (mark != markOopDesc::INFLATING()) {//如果对象不是膨胀中
      // Only do diagnostics if we are not racing an inflation. Simply
      // exiting a recursive enter of a Java Monitor that is being
      // inflated is safe; see the has_monitor() comment below.
      if (mark->has_monitor()) {//判断是否有重量级锁对象
        // The BasicLock's displaced_header is marked as a recursive
        // enter and we have an inflated Java Monitor (ObjectMonitor).
        // This is a special case where the Java Monitor was inflated
        // after this thread entered the stack-lock recursively. When a
        // Java Monitor is inflated, we cannot safely walk the Java
        // Monitor owner's stack and update the BasicLocks because a
        // Java Monitor can be asynchronously inflated by a thread that
        // does not own the Java Monitor.
        ObjectMonitor * m = mark->monitor();//获取锁对象
      }
    }
#endif
    return;//返回
  }

  if (mark == (markOop) lock) {//如果头部mark等于当前锁对象
    if (object->cas_set_mark(dhw, mark) == mark) {//cas替换mark头部为dhw
      return;//直接返回
    }
  }
  //锁膨胀后,进入exit方法
  ObjectSynchronizer::inflate(THREAD,
                              object,
                              inflate_cause_vm_internal)->exit(true, THREAD);
}

ObjectMonitor::exit

void ObjectMonitor::exit(bool not_suspended, TRAPS) {
  Thread * const Self = THREAD;//获取当前的线程对象
  if (THREAD != _owner) {//如果当前线程不等于锁对象的拥有者_owner线程
    if (THREAD->is_lock_owned((address) _owner)) {//如果当前线程栈上的锁拥有者是当前_owner。此种情况可能是当业务持有轻量级锁在执行业务时,遇到了锁膨胀的过程,锁升级成重量级锁了
      _owner = THREAD;
      _recursions = 0;
    } else {
      return;//直接返回
    }
  }

  if (_recursions != 0) {//锁重入,将当前重入次数减去1
    _recursions--;        // this is simple recursive enter
    return;
  }

  _Responsible = NULL;

  for (;;) {
    OrderAccess::release_store(&_owner, (void*)NULL);   // 释放锁,这里释放后,其他线程就可以尝试抢锁
    OrderAccess::storeload(); //全屏障保证后续看到的值都是最新的
    if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {//如果_EntryList和_cxq为空直接返回,_succ表示有等待线程,也直接返回
      return;
    }
    if (!Atomic::replace_if_null(THREAD, &_owner)) {//如果当前_owner为空替换为当前线程
      return;//替换失败直接返回
    }

    ObjectWaiter * w = NULL;

    w = _EntryList;//获取_EntryList
    if (w != NULL) {//当前有线程需要继续执行
      ExitEpilog(Self, w);//唤醒继续执行,直接返回
      return;
    }

    w = _cxq;//获取竞争队列
    if (w == NULL) continue;//队列为空,继续循环
    for (;;) {//for循环将_cxq队列的值取出来并将_cxq队列置为空,
      ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);//将_cxq队列置为空。
      if (u == w) break;
      w = u;
    }


    _EntryList = w;//将cxq队列赋值给_EntryList
    ObjectWaiter * q = NULL;
    ObjectWaiter * p;
    for (p = w; p != NULL; p = p->_next) {//遍历节点修改状态,链表反转
      guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
      p->TState = ObjectWaiter::TS_ENTER;
      p->_prev = q;
      q = p;
    }

    if (_succ != NULL) continue;//_succ不为空,表示有线程唤醒待执行

    w = _EntryList;//获取_EntryList的任务
    if (w != NULL) {//不为空,唤醒后续线程继续执行
      guarantee(w->TState == ObjectWaiter::TS_ENTER, "invariant");
      ExitEpilog(Self, w);
      return;
    }
  }
}

ObjectMonitor::ExitEpilog

void ObjectMonitor::ExitEpilog(Thread * Self, ObjectWaiter * Wakee) {
  // Exit protocol:
  // 1. ST _succ = wakee
  // 2. membar #loadstore|#storestore;
  // 2. ST _owner = NULL
  // 3. unpark(wakee)

  _succ = Wakee->_thread;//_succ置为要唤醒的线程
  ParkEvent * Trigger = Wakee->_event;//获取线程阻塞的事件对象

  // Hygiene -- once we've set _owner = NULL we can't safely dereference Wakee again.
  // The thread associated with Wakee may have grabbed the lock and "Wakee" may be
  // out-of-scope (non-extant).
  Wakee  = NULL;//置空

  // Drop the lock 发布订阅,同时加上全屏障,保证后续可以看到变量的最新值
  OrderAccess::release_store(&_owner, (void*)NULL);
  OrderAccess::fence();                              

  DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self);
  Trigger->unpark();//唤醒线程

  // Maintain stats and report events to JVMTI
  OM_PERFDATA_OP(Parks, inc());
}

4.留言

这些只是个人整理的知识点,中间可能有不到位的地方,烦请各位大佬指出

posted @ 2023-06-28 19:27  bug的自我救赎  阅读(86)  评论(0编辑  收藏  举报