Open monsterhxw opened 10 months ago
CASE(_monitorenter)::bytecodeInterpreter |-lockee = STACK_OBJECT(-1) // 获取锁对象 |-if (entry != NULL) // 找到空闲的 BasicObjectLock (即 Lock Record) | |-entry->set_obj(lockee) // BasicObjectLock->_obj 设置锁对象 | |-success = false | |-mark = lockee->mark() // 获取锁对象 markword | |-if (mark->has_bias_pattern()) // 锁对象 mark word 是否有偏向锁标志位,即 101 | | |-if (anticipated_bias_locking_value == 0) // markword 的线程 ID 就是当前线程而且「锁对象」的 markword 的 epoch 等于「锁对象的类」的 epoch | | |-else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) // 如果偏向模式关闭,则「撤销」偏向锁 | | |-else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) // 如果 epoch 已过期,则需要重偏向 | | |-else { // 1. 要么匿名偏向 2. 要么「已经偏向别的线程」 | | | | // CAS 操作尝试以「匿名偏向 (即线程 ID 为 0) 的 markword」作为比较值,以「偏向当前线程的 markword」作为替换值,设置「锁对象的 markword」值 | | | |-if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), header) == header) | | | |-else // 失败,证明存在多线程竞争,,则调用 monitorenter 进行「偏向撤销 (由 VM 线程撤销)」
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/basicLock.hpp#L32-L78
// BasicObjectLock class BasicObjectLock VALUE_OBJ_CLASS_SPEC { friend class VMStructs; private: // BasicLock 保存 Lock Record 即保存「锁对象」的 markword BasicLock _lock; // the lock, must be double word aligned // 锁对象 oop _obj; // object holds the lock; public: // Manipulation oop obj() const { return _obj; } void set_obj(oop obj) { _obj = obj; } BasicLock* lock() { return &_lock; } }; // BasicLock class BasicLock VALUE_OBJ_CLASS_SPEC { friend class VMStructs; private: // 这里就是保存「锁对象」的 markword volatile markOop _displaced_header; public: markOop displaced_header() const { return _displaced_header; } void set_displaced_header(markOop header) { _displaced_header = header; } };
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp#L94-L612
class BytecodeInterpreter : StackObj { private: JavaThread* _thread; // the vm's java thread pointer address _bcp; // instruction pointer intptr_t* _locals; // local variable pointer ConstantPoolCache* _constants; // constant pool cache Method* _method; // method being executed DataLayout* _mdx; // compiler profiling data for current bytecode intptr_t* _stack; // expression stack messages _msg; // frame manager <-> interpreter message frame_manager_message _result; // result to frame manager interpreterState _prev_link; // previous interpreter state oop _oop_temp; // mirror for interpreted native, null otherwise intptr_t* _stack_base; // base of expression stack intptr_t* _stack_limit; // limit of expression stack // 管程 monitor 的栈底 BasicObjectLock (即 Lock Record) BasicObjectLock* _monitor_base; // base of monitors on the native stack
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp#L1816-L1921
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; // 从栈底到栈顶遍历本地基础锁的栈,找到空闲的 BasicObjectLock (即 Lock Record) while (most_recent != limit ) { if (most_recent->obj() == NULL) entry = most_recent; else if (most_recent->obj() == lockee) break; most_recent++; } // 找到空闲的 BasicObjectLock (即 Lock Record) if (entry != NULL) { // BasicObjectLock->_obj 设置锁对象 entry->set_obj(lockee); int success = false; // 获取 epoc 位置 uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place; // 获取锁对象 markword markOop mark = lockee->mark(); intptr_t hash = (intptr_t) markOopDesc::no_hash; // mark word 是否有偏向锁标志位,即 101 // 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); // anticipated_bias_locking_value==0 代表代表偏向线程就是当前线程,或者重入 // 1. markword 的线程 ID 就是当前线程 // 2. 而且「锁对象」的 markword 的 epoch 等于「锁对象的类」的 epoch if (anticipated_bias_locking_value == 0) { // already biased towards this thread, nothing to do if (PrintBiasedLockingStatistics) { (* BiasedLocking::biased_lock_entry_count_addr())++; } // 这里设置 sucess 是为了不走下面的「轻量级锁」的逻辑 success = true; // 说明是偏向锁重入,也就是之前已经分配了一个BasicObjectLock,那么执行到这里就结束了。 // 该对象有几个BasicObjectLock,就表示重入了几次。 } // 如果偏向模式关闭,则「撤销」偏向锁 else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) { // try revoke bias // 获取「锁对象类」的 markword 对象 markOop header = lockee->klass()->prototype_header(); if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } // CAS 将锁对象的 markword 替换为 class 中的 markword if (Atomic::cmpxchg_ptr(header, lockee->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) (*BiasedLocking::revoked_lock_entry_count_addr())++; } } // 如果 epoch 已过期,则需要重偏向 else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) { // try rebias // 创建一个偏向当前线程的 markword markOop new_header = (markOop) ( (intptr_t) lockee->klass()->prototype_header() | thread_ident); if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } // CAS 替换当前锁对象的 markword if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) (* BiasedLocking::rebiased_lock_entry_count_addr())++; } // 重偏向失败, 说明存在多线程竞争,则调用 monitorenter 进行锁升级 else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } // 这里设置 sucess 是为了不走下面的「轻量级锁」的逻辑 success = true; } // 1. 要么匿名偏向 2. 要么「已经偏向别的线程」 else { // try to bias towards thread in case object is anonymously biased // 构建匿名偏向 (即线程 ID 为 0)的 markword markOop header = (markOop) ((uintptr_t) mark & ((uintptr_t)markOopDesc::biased_lock_mask_in_place | (uintptr_t)markOopDesc::age_mask_in_place | epoch_mask_in_place)); if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } // 加上当前线程 id markOop new_header = (markOop) ((uintptr_t) header | thread_ident); // debugging hint DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) // CAS 将匿名偏向 (即线程 ID 为 0) 的 markword 替换为「偏向当前线程的 markword」 if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), header) == header) { if (PrintBiasedLockingStatistics) (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; } // 失败,证明存在多线程竞争,,则调用 monitorenter 进行锁升级 else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } // 这里设置 sucess 是为了不走下面的「轻量级锁」的逻辑 success = true; } } // 1. 要么偏向标识为 0 2. 要么是偏向锁的撤销 // 轻量级锁逻辑 // traditional lightweight locking if (!success) { // 将当前锁对象的 mark word 与 01 无锁标识,构建新的 markword 且是无锁的 markOop displaced = lockee->mark()->set_unlocked(); // 让指向当前对象的 BasicObjectLock->_lock->_displaced_header 保存该锁对象的无锁 markword entry->lock()->set_displaced_header(displaced); // UseHeavyMonitors是虚拟机可配置项,表示是否直接开启重量级锁,并禁用偏向和轻量锁 bool call_vm = UseHeavyMonitors; // UseHeavyMonitors 开启或者 CAS 尝试将锁对象的 markword 替换为 BasicObjectLock (Lock Record) 的地址,前提是 markword 是无锁状态 if (call_vm || Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) { // Is it simple recursive case? if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { // 这里是 UseHeavyMonitors 关闭,虽然 CAS 失败,再次判断当前线程是否拥有锁对象,是代表锁重入 // 则直接将 Displaced Mark Word 设置为 null // 轻量级锁重入是使用 lock record 的数量来计入的 entry->lock()->set_displaced_header(NULL); } else { // UseHeavyMonitors 开启或者,CAS 失败 (说明发生锁竞争,即锁对象不是无锁状态) // 走锁升级逻辑 CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } } } UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } else { // 没拿到 lock record,重新执行 istate->set_msg(more_monitors); UPDATE_PC_AND_RETURN(0); // Re-execute } }
InterpreterRuntime::monitorenter
UseHeavyMonitors
CASE(_monitorenter)::bytecodeInterpreter |-lockee = STACK_OBJECT(-1) // 获取锁对象 |-if (entry != NULL) // 找到空闲的 BasicObjectLock (即 Lock Record) | |-entry->set_obj(lockee) // BasicObjectLock->_obj 设置锁对象 | |-success = false | |-mark = lockee->mark() // 获取锁对象 markword | |-if (mark->has_bias_pattern()) // 锁对象 mark word 是否有偏向锁标志位,即 101 | | |-if (anticipated_bias_locking_value == 0) // markword 的线程 ID 就是当前线程而且「锁对象」的 markword 的 epoch 等于「锁对象的类」的 epoch | | |-else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) // 如果偏向模式关闭,则「撤销」偏向锁 | | |-else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) // 如果 epoch 已过期,则需要重偏向 | | |-else { // 1. 要么匿名偏向 2. 要么「已经偏向别的线程」 | | | | // CAS 操作尝试以「匿名偏向 (即线程 ID 为 0) 的 markword」作为比较值,以「偏向当前线程的 markword」作为替换值,设置「锁对象的 markword」值 | | | |-if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), header) == header) | | | |-else // CAS 失败,证明存在多线程竞争,,则调用 monitorenter 进行锁升级 | | | | |-CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception) | | | | | | |-monitorenter(THREAD, entry)::InterpreterRuntime | | | | | | |-if (UseBiasedLocking) // jvm 可配置参数是否开启了偏向锁 | | | | | | | |-fast_enter(h_obj, elem->lock(), true, CHECK)::ObjectSynchronizer | | | | | | | | |-if (UseBiasedLocking) // jvm 可配置参数是否开启了偏向锁 | | | | | | | | | |-if (!SafepointSynchronize::is_at_safepoint()) // 当前不处于 safepoint (正常 Java 线程走这里) | | | | | | | | | | |-cond = revoke_and_rebias(obj, attempt_rebias, THREAD)::BiasedLocking // 执行 revoke_and_rebias 方法,即执行「撤销」或「重偏向」 | | | | | | | | | | | |-heuristics = update_heuristics(obj(), attempt_rebias) | | | | | | | | | | | |-if (heuristics == HR_SINGLE_REVOKE) // // 撤销单个线程 **最常见的执行分支** | | | | | | | | | | | | |-if (mark->biased_locker() == THREAD && prototype_header->bias_epoch() == mark->bias_epoch()) // 如果当前线程是偏向线程 | | | | | | | | | | | | |-else // 因为当前线程不是偏向线程,所以由 VMThread 执行撤销 revoke,最终会在 safepoint 调用 revoke_bias 方法撤销偏向 | | | | | | | | | | | | | |-VM_RevokeBias revoke(&obj, (JavaThread*) THREAD) | | | | | | | | | | | | | |-VMThread::execute(&revoke) | | | | | | | | | | | | | | | // 判断偏向线程 T1 是否还存活 | | | | | | | | | | | | | | | // 不存活,若允许重偏向,设置 markword 匿名偏向,不允许则设置 markword 为无锁模式,都返回 BIAS_REVOKED | | | | | | | | | | | | | | | // 存活且还在同步代块里,需要升级为轻量级锁,直接修改偏向线程栈中的 Lock Record。 | | | | | | | | | | | | | | | // 存活且不在同步代块里,若允许重偏向,设置 markword 匿名偏向,不允许则设置 markword 为无锁模式,都返回 BIAS_REVOKED
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp#L620-L641
IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem)) #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif if (PrintBiasedLockingStatistics) { Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); } Handle h_obj(thread, elem->obj()); assert(Universe::heap()->is_in_reserved_or_null(h_obj()), "must be NULL or an object"); // jvm 可配置参数是否开启了偏向锁 if (UseBiasedLocking) { // Retry fast entry if bias is revoked to avoid unnecessary inflation // 开启了偏向锁走的就是 ObjectSynchronizer::fast_enter 的方法 ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK); } else { ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK); } assert(Universe::heap()->is_in_reserved_or_null(elem->obj()), "must be NULL or an object"); #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif IRT_END
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/synchronizer.cpp#L169-L184
void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) { // jvm 可配置参数是否开启了偏向锁 if (UseBiasedLocking) { // 当前不处于 safepoint (正常 Java 线程走这里) if (!SafepointSynchronize::is_at_safepoint()) { // 执行 revoke_and_rebias 方法,即执行「撤销」和「重偏向」 BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD); // 返回值是 BIAS_REVOKED_AND_REBIASED (即等于 3),直接返回,否则执行 slow_enter 方法 if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) { return; } } else { // 处于 safepoint (VM 线程会走这里) assert(!attempt_rebias, "can not rebias toward VM thread"); // 执行 revoke_at_safepoint 方法,即执行在 safe point 进行撤销 BiasedLocking::revoke_at_safepoint(obj); // 会执行下面 slow_enter 方法 } assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); } // 或者 “JVM 没有开启偏向锁” // 或者 “JVM 开启偏向锁” + “不处于 safepoint” + “调用 BiasedLocking::revoke_and_rebias” 返回不等于 BIAS_REVOKED_AND_REBIASED // 或者 “JVM 开启偏向锁” + “处于 safepoint” // 上面任一条件满足都会执行 slow_enter 方法 slow_enter (obj, lock, THREAD) ; }
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/biasedLocking.hpp#L161-L165
enum Condition { NOT_BIASED = 1, BIAS_REVOKED = 2, BIAS_REVOKED_AND_REBIASED = 3 };
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/biasedLocking.cpp#L554-L676
BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); // 获取锁对象的 markword markOop mark = obj->mark(); // 如果是匿名偏向 (ThreadID=0) 且 attempt_rebias (是否运行重偏向) 为 false // 如锁对象的hashcode方法被调用会出现这种情况,需要撤销偏向锁。 if (mark->is_biased_anonymously() && !attempt_rebias) { markOop biased_value = mark; // 创建无锁的 markword (hash 置为 0 & 锁状态置为无锁(001)& 分代年龄置为当前对象的分代[nohash|age|001]) markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); // 以「无锁 markword」作为替换值,以「锁对象的 wordword」作为比较值,CAS 设置「锁对象的 markword 内存」 markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark); // CAS 成功 if (res_mark == biased_value) { // 返回「偏向锁撤销状态 (BIAS_REVOKED=2)」,会调用 slow_enter 方法 return BIAS_REVOKED; } } else if (mark->has_bias_pattern()) { // 若锁对象 markword 有偏向锁标识 (101) Klass* k = obj->klass(); markOop prototype_header = k->prototype_header(); // 锁对象的类 Class 的对象的 markword 关闭了偏向锁,即 markword 没有偏向标识 (101) if (!prototype_header->has_bias_pattern()) { markOop biased_value = mark; // 以「锁对象类的 markword」作为替换值,以「锁对象的 wordword」作为比较值,CAS 设置「锁对象的 markword 内存」 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"); // 不管 CAS 成功或失败,都返回「偏向锁撤销状态 (BIAS_REVOKED=2)」,会调用 slow_enter 方法 return BIAS_REVOKED; } else if (prototype_header->bias_epoch() != mark->bias_epoch()) { // 锁对象的 markword 的 epoch 过期 // 是否进行重偏向 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()); // 以「重偏向当前线程 markword」作为替换值,以「锁对象的 wordword」作为比较值,CAS 设置「锁对象的 markword 内存」 markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark); // 重偏向成功,返回「偏向锁撤销且重偏向 (BIAS_REVOKED_AND_REBIASED=3)」,不会调用 slow_enter 方法 if (res_mark == biased_value) { return BIAS_REVOKED_AND_REBIASED; } } else { // 不需要进行重偏向 markOop biased_value = mark; // 创建无锁的 markword (hash 置为 0 & 锁状态置为无锁(001)& 分代年龄置为当前对象的分代[nohash|age|001]) markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); // 以「无锁 markword」作为替换值,以「锁对象的 wordword」作为比较值,CAS 设置「锁对象的 markword 内存」 markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark); // CAS 成功,返回「偏向锁撤销状态 (BIAS_REVOKED=2)」,会调用 slow_enter 方法 if (res_mark == biased_value) { return BIAS_REVOKED; } } } } // 执行到这里有以下两种情况:1. 锁对象不是偏向模式 2. 上面的 cas 操作失败 // 批量重偏向与批量撤销的逻辑 HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias); // 锁对象的 markword 不是偏向锁,返回「不是偏向锁 (NOT_BIASED=1)」,会执行 slow_enter if (heuristics == HR_NOT_BIASED) { return NOT_BIASED; } else if (heuristics == HR_SINGLE_REVOKE) { // 撤销单个线程 **最常见的执行分支** Klass *k = obj->klass(); markOop prototype_header = k->prototype_header(); // 锁对象的 markword 的偏向 thread_id 是当前线程 & epoch 没有过期 // 走到这里说明需要撤销的是偏向当前线程的锁,当调用 Object#hashcode 方法时会走到这一步 // 因为只要遍历当前线程的栈就好了,所以不需要等到 safepoint 再撤销。 if (mark->biased_locker() == THREAD && prototype_header->bias_epoch() == mark->bias_epoch()) { ResourceMark rm; if (TraceBiasedLocking) { tty->print_cr("Revoking bias by walking my own stack:"); } EventBiasedLockSelfRevocation event; // 调用 revoke_bias 撤销偏向锁 BiasedLocking::Condition cond = revoke_bias(obj(), false, false, (JavaThread*) THREAD, NULL); ((JavaThread*) THREAD)->set_cached_monitor_info(NULL); assert(cond == BIAS_REVOKED, "why not?"); if (event.should_commit()) { event.set_lockClass(k); event.commit(); } // 返回「偏向锁撤销状态 (BIAS_REVOKED=2)」,会调用 slow_enter 方法 return cond; } else { EventBiasedLockRevocation event; // 由 VMThread 执行撤销 revoke,最终会在 safepoint 调用 revoke_bias 方法撤销偏向 VM_RevokeBias revoke(&obj, (JavaThread*) THREAD); VMThread::execute(&revoke); if (event.should_commit() && (revoke.status_code() != NOT_BIASED)) { event.set_lockClass(k); // Subtract 1 to match the id of events committed inside the safepoint event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); event.set_previousOwner(revoke.biased_locker()); event.commit(); } // 返回结果 return revoke.status_code(); } } // 批量撤销、批量重偏向的逻辑 assert((heuristics == HR_BULK_REVOKE) || (heuristics == HR_BULK_REBIAS), "?"); EventBiasedLockClassRevocation event; VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD, (heuristics == HR_BULK_REBIAS), attempt_rebias); VMThread::execute(&bulk_revoke); if (event.should_commit()) { event.set_revokedClass(obj->klass()); event.set_disableBiasing((heuristics != HR_BULK_REBIAS)); // Subtract 1 to match the id of events committed inside the safepoint event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); event.commit(); } return bulk_revoke.status_code(); }
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/biasedLocking.cpp#L278-L328
static HeuristicsResult update_heuristics(oop o, bool allow_rebias) { markOop mark = o->mark(); // 判断是否是偏向模式 if (!mark->has_bias_pattern()) { // 返回不是偏向标识 return HR_NOT_BIASED; } 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(); // 如果已撤销的次数大于批量重偏向的次数,并小于批量撤销的次数 // 并且撤销时间不为 0,也就是被初始化过,并且时间间隔大于重置的阈值 if ((revocation_count >= BiasedLockingBulkRebiasThreshold) && (revocation_count < BiasedLockingBulkRevokeThreshold) && (last_bulk_revocation_time != 0) && (cur_time - last_bulk_revocation_time >= BiasedLockingDecayTime)) { // 将撤销的次数重置为 0 k->set_biased_lock_revocation_count(0); revocation_count = 0; } // Make revocation count saturate just beyond BiasedLockingBulkRevokeThreshold // // 如果撤销的次数小于批量撤销次数 +1 if (revocation_count <= BiasedLockingBulkRevokeThreshold) { revocation_count = k->atomic_incr_biased_lock_revocation_count(); } // 如果达到「批量撤销阈值」则返回相应标识 if (revocation_count == BiasedLockingBulkRevokeThreshold) { return HR_BULK_REVOKE; } // 如果达到「批量重偏向阈值」则返回相应标识 if (revocation_count == BiasedLockingBulkRebiasThreshold) { return HR_BULK_REBIAS; } // 返回撤销单个对象的锁标识 return HR_SINGLE_REVOKE; }
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/biasedLocking.cpp#L149-L267
static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread, JavaThread** biased_locker) { markOop mark = obj->mark(); // 如果没有开启偏向模式即 markword 没有偏向标识 (101),则直接返回 NOT_BIASED if (!mark->has_bias_pattern()) { if (TraceBiasedLocking) { ResourceMark rm; tty->print_cr(" (Skipping revocation of object of type %s because it's no longer biased)", obj->klass()->external_name()); } return BiasedLocking::NOT_BIASED; } uint age = mark->age(); // 构建两个 mark word,一个是匿名偏向模式(101),一个是无锁模式(001) markOop biased_prototype = markOopDesc::biased_locking_prototype()->set_age(age); markOop unbiased_prototype = markOopDesc::prototype()->set_age(age); if (TraceBiasedLocking && (Verbose || !is_bulk)) { ResourceMark rm; tty->print_cr("Revoking bias of object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s , prototype header " INTPTR_FORMAT " , allow rebias %d , requesting thread " INTPTR_FORMAT, p2i((void *)obj), (intptr_t) mark, obj->klass()->external_name(), (intptr_t) obj->klass()->prototype_header(), (allow_rebias ? 1 : 0), (intptr_t) requesting_thread); } JavaThread* biased_thread = mark->biased_locker(); // 锁对象 markwork 的是匿名偏向 if (biased_thread == NULL) { // 不允许重偏向 if (!allow_rebias) { // 设置锁对象 markword 为无锁模式 (001) obj->set_mark(unbiased_prototype); } if (TraceBiasedLocking && (Verbose || !is_bulk)) { tty->print_cr(" Revoked bias of anonymously-biased object"); } 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) { thread_is_alive = true; } else { // 当前线程不是偏向线程,遍历当前jvm的所有线程,如果能找到,则说明偏向的线程还存活 for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) { if (cur_thread == biased_thread) { thread_is_alive = true; break; } } } // 如果偏向的线程已经不存活了 if (!thread_is_alive) { // 允许重偏向 if (allow_rebias) { // 设置将锁对象 mark word 设置为匿名偏向状态 obj->set_mark(biased_prototype); } else { // 设置将锁对象 mark word 设置为无锁模式 obj->set_mark(unbiased_prototype); } if (TraceBiasedLocking && (Verbose || !is_bulk)) { tty->print_cr(" Revoked bias of object biased toward dead thread"); } return BiasedLocking::BIAS_REVOKED; } // 线程还存活则遍历线程栈中所有的 Lock Record 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); // 如果能找到对应的 Lock Record 说明偏向的线程还在执行同步代码块中的代码 if (mon_info->owner() == obj) { if (TraceBiasedLocking && Verbose) { tty->print_cr(" mon_info->owner (" PTR_FORMAT ") == obj (" PTR_FORMAT ")", p2i((void *) mon_info->owner()), p2i((void *) obj)); } // Assume recursive case and fix up highest lock later // 需要升级为轻量级锁,直接修改偏向线程栈中的 Lock Record。 // 为了处理锁重入的 case,在这里将 Lock Record 的 Displaced Mark Word 设置为 null,第一个 Lock Record 会在下面的代码中再处理 markOop mark = markOopDesc::encode((BasicLock*) NULL); highest_lock = mon_info->lock(); highest_lock->set_displaced_header(mark); } else { if (TraceBiasedLocking && Verbose) { tty->print_cr(" mon_info->owner (" PTR_FORMAT ") != obj (" PTR_FORMAT ")", p2i((void *) mon_info->owner()), p2i((void *) obj)); } } } if (highest_lock != NULL) { // 修改第一个 Lock Record 为无锁状态,然后将 obj 的 mark word 设置为指向该 Lock Record 的指针 highest_lock->set_displaced_header(unbiased_prototype); obj->release_set_mark(markOopDesc::encode(highest_lock)); assert(!obj->mark()->has_bias_pattern(), "illegal mark state: stack lock used bias bit"); if (TraceBiasedLocking && (Verbose || !is_bulk)) { tty->print_cr(" Revoked bias of currently-locked object"); } } else { // 走到这里说明偏向线程已经不在同步块中了 if (TraceBiasedLocking && (Verbose || !is_bulk)) { tty->print_cr(" Revoked bias of currently-unlocked object"); } // 允许重偏向,设置为匿名偏向状态 if (allow_rebias) { obj->set_mark(biased_prototype); } else { // 不允许重偏向,设置为无锁模式 (001) // Store the unlocked value into the object's header. obj->set_mark(unbiased_prototype); } } #if INCLUDE_JFR // If requested, return information on which thread held the bias if (biased_locker != NULL) { *biased_locker = biased_thread; } #endif // INCLUDE_JFR return BiasedLocking::BIAS_REVOKED; }
CASE(_monitorexit)::bytecodeInterpreter
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp#L1923-L1953
CASE(_monitorexit): { oop lockee = STACK_OBJECT(-1); // 锁对象 CHECK_NULL(lockee); BasicObjectLock* limit = istate->monitor_base(); BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base(); while (most_recent != limit ) { // 从栈底遍历到栈顶 // 找到 BasicObjectLock (即 LockRecord) 的 obj 等于锁对象 if ((most_recent)->obj() == lockee) { // 获取锁 BasicLock* lock = most_recent->lock(); markOop header = lock->displaced_header(); // 设置将 BasicObjectLock (即 LockRecord) 中的_obj设置为空 // 如果是偏向锁,只需要释放 BasicObjectLock (即 LockRecord) 就行 most_recent->set_obj(NULL); if (!lockee->mark()->has_bias_pattern()) { // 如果不是偏向锁,走轻量级或者重量级锁的释放流程 bool call_vm = UseHeavyMonitors; // If it isn't recursive we either must swap old header or call the runtime if (header != NULL || call_vm) { // header 为空即代表轻量级锁重入,轻量级锁只需要处理第一次 Lock Record if (call_vm || Atomic::cmpxchg_ptr(header, lockee->mark_addr(), lock) != lock) { // CAS 设置为原来 markword (即存放在 Lock Record 的 markword) // restore object for the slow case most_recent->set_obj(lockee); CALL_VM(InterpreterRuntime::monitorexit(THREAD, most_recent), handle_exception); } } } UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); // 执行下一条命令 } most_recent++; } CALL_VM(InterpreterRuntime::throw_illegal_monitor_state_exception(THREAD), handle_exception); ShouldNotReachHere(); }
-XX:BiasedLockingStartupDelay 参数可修改
-XX:BiasedLockingStartupDelay
原因是偏向锁的撤销,是需要 VM 线程在 safepoint 进行单个/批量将具有偏向锁的锁对象,进行撤销为「无锁」或者为「轻量级锁」,会导致 STW 时间加长,性能不好
synchronized 分析
获取偏向锁
BasicObjectLock 和 BasicLock 定义
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/basicLock.hpp#L32-L78
BytecodeInterpreter 定义
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp#L94-L612
bytecodeInterpreter | #define ARRAY_STOREFROM64 | CASE(_monitorenter)
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp#L1816-L1921
能获取偏向锁的条件
执行轻量级锁的逻辑条件
执行 InterpreterRuntime::monitorenter 方法的条件
InterpreterRuntime::monitorenter
方法InterpreterRuntime::monitorenter
方法UseHeavyMonitors
直接开启重量级锁,并禁用偏向锁和轻量级锁,会执行InterpreterRuntime::monitorenter
方法InterpreterRuntime::monitorenter
方法竞争偏向锁失败,让 VM 线程进行偏向锁撤销为无锁或轻量级锁
InterpreterRuntime::monitorenter 方法
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp#L620-L641
ObjectSynchronizer::fast_enter 方法
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/synchronizer.cpp#L169-L184
BiasedLocking#Condition 枚举定义
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/biasedLocking.hpp#L161-L165
BiasedLocking::revoke_and_rebias 撤销和重偏向方法
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/biasedLocking.cpp#L554-L676
BiasedLocking::update_heuristics 更新 heuristic方法
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/biasedLocking.cpp#L278-L328
BiasedLocking::revoke_bias 撤销偏向锁方法
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/biasedLocking.cpp#L149-L267
释放偏向锁
bytecodeInterpreter 方法 bytecodeInterpreter | #define ARRAY_STOREFROM64 | CASE(_monitorexit)
源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp#L1923-L1953