(资料图)
深入浅出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中的_monitorenterCASE(_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::monitorenterIRT_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_entervoid 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_rebiasBiasedLocking::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_safepointvoid 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_heuristicsstatic 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_safepointstatic 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* 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* 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* 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_entervoid 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::inflateObjectMonitor* 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::entervoid 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 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::EnterIvoid 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::TryLockint 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::TrySpinint 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中的_monitorexitCASE(_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::monitorexitIRT_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::exitvoid 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::ExitEpilogvoid 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.留言这些只是个人整理的知识点,中间可能有不到位的地方,烦请各位大佬指出
标签: