從wait的源碼看撤銷偏向鎖的過程(revoke and rebias)

wait源碼實現以下java

//TRAPS表示是否有異常
void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
  if (UseBiasedLocking) {
    //若是是使用了偏向鎖,要撤銷偏向鎖
    BiasedLocking::revoke_and_rebias(obj, false, THREAD);
    assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
  }
 ...
複製代碼

biasedLocking.cpp中能夠看到方法的實現。總體結構劃分以下安全

BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {
//1:必須在安全點
assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");
//2:讀取對象頭
markOop mark = obj->mark();
if (mark->is_biased_anonymously() && !attempt_rebias) {
//3:沒有線程獲取了偏向鎖
} else if (mark->has_bias_pattern()) {
//4:已經偏向了
}
//5:沒有執行偏向,經過啓發式的方式決定究竟是執行撤銷仍是執行rebias
HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias);
if (heuristics == HR_NOT_BIASED) {
//5.1:偏向狀態改爲了不須要偏向
} else if (heuristics == HR_SINGLE_REVOKE) {
//5.2:啓發式決定執行單次的撤銷
}
//6:等到虛擬機運行到safepoint,實際就是執行  VM_BulkRevokeBias 的doit的 bulk_revoke_or_rebias_at_safepoint方法
VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD,
                              (heuristics == HR_BULK_REBIAS),
                              attempt_rebias);
VMThread::execute(&bulk_revoke);
return bulk_revoke.status_code();
}
複製代碼

沒有獲取偏向鎖

這裏表示尚未被偏向,而且不是執行rebiasbash

// 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;
//prootype自己構建的是 markOop( no_hash_in_place | no_lock_in_place );
markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
//執行CAS,若是當前對象的mark沒有變動,就換成 unbiased_prototype
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
  //若是以前的和如今的同樣,說明撤銷成功,BIAS_REVOKED自己是一個枚舉  
return BIAS_REVOKED;
}
複製代碼

已經被其它線程獲取了偏向

//已經被線程偏向了,獲取Klass對象,即類自己的頭,obj則是它的實例 
Klass* k = Klass::cast(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 = (markOop) Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark);
   assert(!(*(obj->mark_addr()))->has_bias_pattern(), "even if we raced, should still be revoked");
   return BIAS_REVOKED;
 } else if (prototype_header->bias_epoch() != mark->bias_epoch()) {
   //實例的epoch和類自己的epoch值不同,說明它已通過期,也就是說這個對象當前處於未偏向可是可偏向的狀態(rebiasable)   
// 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) { //執行rebias wait但願直接撤銷 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 = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark); if (res_mark == biased_value) { //當前線程搶到了這個對象的偏向 return BIAS_REVOKED_AND_REBIASED; } } else { markOop biased_value = mark; markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); //CAS撤銷偏向鎖 markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark); if (res_mark == biased_value) { //撤銷了偏向 return BIAS_REVOKED; } } } 複製代碼

啓發式策略

//啓發式的方式決定要作那種操做static HeuristicsResult update_heuristics(oop o, bool allow_rebias) {
  markOop mark = o->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->blueprint(); jlong cur_time = os::javaTimeMillis(); //獲取上次執行bulk revication的時間 jlong last_bulk_revocation_time = k->last_biased_lock_bulk_revocation_time(); //獲取執行bulk revocation的次數 int revocation_count = k->biased_lock_revocation_count(); //定義在globs.hpp,BiasedLockingBulkRebiasThreshold取值爲20;BiasedLockingBulkRevokeThreshold取值爲40,BiasedLockingDecayTime爲25000毫秒 if ((revocation_count >= BiasedLockingBulkRebiasThreshold) && (revocation_count < BiasedLockingBulkRevokeThreshold) && (last_bulk_revocation_time != 0) && (cur_time - last_bulk_revocation_time >= BiasedLockingDecayTime)) { // 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. //在執行了必定時間以內,執行的撤銷次數沒有超過閾值,那麼認爲能夠優先執行bulk rebias,所以將計數迴歸原始值 k->set_biased_lock_revocation_count(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) { //達到執行bulk revoke的閾值,執行bulk revoke return HR_BULK_REVOKE; } if (revocation_count == BiasedLockingBulkRebiasThreshold) { //達到 bulk rebias的閾值,執行bulk rebias return HR_BULK_REBIAS; } //默認執行單次的撤銷 return HR_SINGLE_REVOKE; } 複製代碼

bulk_revoke_or_rebias_at_safepoint

bulk revoke的關鍵在於它會遍歷全部線程棧的每一幀app

static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,
                                                                   bool bulk_rebias,
                                                                   bool attempt_rebias_of_object,
                                                                   JavaThread* requesting_thread) {
…
if (bulk_rebias) {
     ...
  // Now walk all threads' stacks and adjust epochs of any biased // and locked objects of this data type we encounter //遍歷全部的線程 for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->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()) { // We might have encountered this object already in the case of recursive locking assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment"); //更新全部棧中的有偏向鎖的epoch owner->set_mark(mark->set_bias_epoch(cur_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);
}
…
if (attempt_rebias_of_object &&
    o->mark()->has_bias_pattern() &&
    klass->prototype_header()->has_bias_pattern()) {
 //bias_epoch自己則是表示獲取了偏向鎖
  markOop new_mark = markOopDesc::encode(requesting_thread, o->mark()->age(),
                                         klass->prototype_header()->bias_epoch());
  o->set_mark(new_mark);
//執行rebiase
  status_code = BiasedLocking::BIAS_REVOKED_AND_REBIASED;
 ...
}
}
複製代碼

revoke_bias的執行以下less

static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread) {
markOop mark = obj->mark();
…
//偏向鎖的頭
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) {
  //沒有線程獲取,又須要執行rebias,改掉對象頭便可
    obj->set_mark(unbiased_prototype);
  }
 ...
  //撤銷完畢  
  return BiasedLocking::BIAS_REVOKED;
}
…
//線程活着
//遍歷棧幀,獲取全部這個線程的監視器,按照最年輕到最老的順序 
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 (mon_info->owner() == obj) {
   ...
     // Assume recursive case and fix up highest lock later    
 //當前棧幀存在了這個對象的鎖     
    markOop mark = markOopDesc::encode((BasicLock*) NULL);
     highest_lock = mon_info->lock();
     //更新棧中的mark爲NULL     
    highest_lock->set_displaced_header(mark);
   }
...
   }
 }
 if (highest_lock != NULL) {
   // Fix up highest lock to contain displaced header and point   
// object at it   
//將最久的那個lock更新爲沒有偏向  ,棧中  設置了鎖記錄 
highest_lock->set_displaced_header(unbiased_prototype);
   // Reset object header to point to displaced mark   
//將對象頭指向棧中的位置,這樣表示就沒有偏向了
obj->set_mark(markOopDesc::encode(highest_lock));
   assert(!obj->mark()->has_bias_pattern(), "illegal mark state: stack lock used bias bit");
  ...
 } else {
  ...
   if (allow_rebias) {
     obj->set_mark(biased_prototype);
   } else {
     // Store the unlocked value into the object's header. obj->set_mark(unbiased_prototype); } } //撤銷完畢 return BiasedLocking::BIAS_REVOKED; } 複製代碼
相關文章
相關標籤/搜索