深入浅出synchronized的原理与源码
深入浅出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中的_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, 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_enter
void 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_rebias
BiasedLocking::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_safepoint
void 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_heuristics
static 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_safepoint
static 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<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()) {//如果锁对象等于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<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()) {//当前监视器的拥有者对象等于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<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 (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_enter
void 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::inflate
ObjectMonitor* 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::enter
void 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<EventJavaMonitorEnter> 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::EnterI
void 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::TryLock
int 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::TrySpin
int 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中的_monitorexit
CASE(_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::monitorexit
IRT_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::exit
void 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::ExitEpilog
void 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.留言
这些只是个人整理的知识点,中间可能有不到位的地方,烦请各位大佬指出