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, el