Wait source code implementation is as follows

//TRAPS Specifies whether exceptions exist. Void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
  ifBiasedLocking::revoke_and_rebias(obj, revoke_and_rebias(obj,false, THREAD); assert(! obj->mark()->has_bias_pattern(),"biases should be revoked by now"); }...Copy the code

You can see the implementation of the method in biasedLocking. CPP. The overall structure is divided as follows

BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {//1: must be established at safe points (! SafepointSynchronize::is_at_safepoint(),"must not be called while at safepoint"); //2: markOop mark = obj->mark();if(mark->is_biased_anonymously() && ! Attempt_rebias) {//3: No thread acquired bias lock}else if(mark - > has_bias_pattern ()) {/ / 4: it's in favour of the} / / 5: no bias, HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias); attempt_heuristics = update_heuristics(obj(), attempt_rebias);if(heuristics == HR_NOT_BIASED) {//5.1: bias status is changed to no bias required}else if(heuristics == HR_SINGLE_REVOKE) {//5.2: heuristics decide to perform a single revoke} //6: After the VM runs to Safepoint, the bulk_revokebias method VM_BulkRevokeBias of DOIT is executed bulk_revoke(&obj, (JavaThread*) THREAD, (heuristics == HR_BULK_REBIAS), attempt_rebias); VMThread::execute(&bulk_revoke);return bulk_revoke.status_code();
}
Copy the code

No bias lock is obtained

This indicates that it has not been biased and is not 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 ifwe 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; / / build prootype itself are markOop (no_hash_in_place | no_lock_in_place); markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); // Execute CAS. If the mark of the current object has not changed, Atomic:: cMPxchg_ptr (unbiASed_prototype, obj->mark_addr(), mark);if(RES_mark == biASED_value) {// If the previous is the same as the present, the deregistration is successful, BIAS_REVOKED itself is an enumerationreturn BIAS_REVOKED;
}
Copy the code

Bias has been acquired by another thread

Klass* k = Klass::cast(obj-> Klass ()); markOop prototype_header = k->prototype_header();if(! Prototype_header ->has_bias_pattern()) {// The current bias state of the object has expired and is not biased, 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 callerdeal // 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()) {// The epoch of the instance is different from the epoch of the class itself, indicating that it has expired. That is, The object is currently unbiased but rebiasable. // The epoch of this biasing has expired that The object is effectively unbiased. Depending on whether we need // to rebias or revoke the bias of this object we cando 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 // to revoke biases. If (attempt_rebias) {// Execute rebias wait to revoke biases 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 res_mark = (markOop) Atomic:: cMPxchg_ptr (unbiASed_prototype, obj->mark_addr(), mark); If (res_mark == biASed_value) {return BIAS_REVOKED; }}}Copy the code

Heuristic strategy

Static HeuristicsResult update_heuristics(oop O, bool allow_rebias) {markOop mark = o->mark();if(! Mark ->has_bias_pattern()) {// Cannot bias direct returnreturnHR_NOT_BIASED; } // Heuristics to attempt to throttle the number of revocations. // 1. Revoke the biases of all objectsin 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(); Jlong last_bulk_reVOCation_time = k-> last_biased_lock_BULK_reVOCation_time (); Int reVOCation_count = k-> biASED_lock_reVOCation_count (); / / definition in globs HPP, BiasedLockingBulkRebiasThreshold value of 20; BiasedLockingBulkRevokeThreshold value of 40, BiasedLockingDecayTime for 25000 milliseconds 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. // Within a certain period of time, the number of revocations will not exceed the threshold. Bulk rebias is considered to be the priority, so the count is returned to the original value k-> set_BIASED_LOCK_REVOCation_count (0); revocation_count = 0; } // Make revocation count saturate just beyond BiasedLockingBulkRevokeThreshold if (revocation_count <= BiasedLockingBulkRevokeThreshold) {/ / calculates the number of undone revocation_count = k - > atomic_incr_biased_lock_revocation_count (); } the if (revocation_count = = BiasedLockingBulkRevokeThreshold) {/ / to perform bulk revoke threshold, perform bulk revoke return HR_BULK_REVOKE; } the if (revocation_count = = BiasedLockingBulkRebiasThreshold) {/ / to bulk rebias threshold, perform bulk rebias return HR_BULK_REBIAS; } // By default, return HR_SINGLE_REVOKE is executed once; }Copy the code

bulk_revoke_or_rebias_at_safepoint

The key to Bulk REVOKE is that it traverses every frame of all thread stacks

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()) { Get all monitors GrowableArray
      
       * 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"); // Update the epoch owner->set_mark(mark-> set_bias_EPOCH (cur_epoch)) in all stacks with biased locks; }}}... // 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()) { MarkOop new_mark = markOopDesc::encode(o->mark()->age(), klass->prototype_header()->bias_epoch()); o->set_mark(new_mark); // Run rebiase status_code = BiasedLocking::BIAS_REVOKED_AND_REBIASED; . }}Copy the code

Revoke_bias is executed as follows

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(! Obj ->set_mark(unbiased_prototype); }... // Undo completereturnBiasedLocking::BIAS_REVOKED; }... // Thread alive // traverses the stack frame, Get all monitors for this thread, in the order youngest to oldest: 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 caseMarkOop mark = markOopDesc::encode((BasicLock*) NULL); highest_lock = mon_info->lock(); Highest_lock ->set_displaced_header(mark); }... }}if(highest_lock ! // Fix up highest lock to contain swat header and point // object at it // Update the highest lock to contain swat header and point highest_lock->set_displaced_header(unbiased_prototype); // Reset object header to point to function 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; }Copy the code