從wait的原始碼看撤銷偏向鎖的過程(revoke and rebias)
阿新 • • 發佈:2018-12-31
wait原始碼實現如下
//TRAPS表示是否有異常
void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
if (UseBiasedLocking) {
//如果是使用了偏向鎖,要撤銷偏向鎖
BiasedLocking::revoke_and_rebias(obj, false, THREAD);
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
...
在biasedLocking.cpp
BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { //1:必須在安全點 assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); //2:讀取物件頭 markOop mark = obj->mark(); if (mark->is_biased_anonymously() && !attempt_rebias) { //3:沒有執行緒獲取了偏向鎖 } else if (mark->has_bias_pattern()) { //4:已經偏向了 } //5:沒有執行偏向,通過啟發式的方式決定到底是執行撤銷還是執行rebias HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias); if (heuristics == HR_NOT_BIASED) { //5.1:偏向狀態改成了不需要偏向 } else if (heuristics == HR_SINGLE_REVOKE) { //5.2:啟發式決定執行單次的撤銷 } //6:等到虛擬機器執行到safepoint,實際就是執行 VM_BulkRevokeBias 的doit的 bulk_revoke_or_rebias_at_safepoint方法 VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD, (heuristics == HR_BULK_REBIAS), attempt_rebias); VMThread::execute(&bulk_revoke); return bulk_revoke.status_code(); }
沒有獲取偏向鎖
這裡表示還沒有被偏向,並且不是執行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; //prootype本身構建的是 markOop( no_hash_in_place | no_lock_in_place ); markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); //執行CAS,如果當前物件的mark沒有變更,就換成 unbiased_prototype markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark); if (res_mark == biased_value) { //如果之前的和現在的一樣,說明撤銷成功,BIAS_REVOKED本身是一個列舉 return BIAS_REVOKED; }
已經被其它執行緒獲取了偏向
//已經被執行緒偏向了,獲取Klass物件,即類本身的頭,obj則是它的例項
Klass* k = Klass::cast(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 = (markOop) Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark);
assert(!(*(obj->mark_addr()))->has_bias_pattern(), "even if we raced, should still be revoked");
return BIAS_REVOKED;
} else if (prototype_header->bias_epoch() != mark->bias_epoch()) {
//例項的epoch和類本身的epoch值不一樣,說明它已經過期,也就是說這個物件當前處於未偏向但是可偏向的狀態(rebiasable)
// 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) {
//執行rebias wait希望直接撤銷
assert(THREAD->is_Java_thread(), "");
markOop biased_value = mark;
markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch());
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
//當前執行緒搶到了這個物件的偏向
return BIAS_REVOKED_AND_REBIASED;
}
} else {
markOop biased_value = mark;
markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
//CAS撤銷偏向鎖
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
//撤銷了偏向
return BIAS_REVOKED;
}
}
}
啟發式策略
//啟發式的方式決定要做那種操作static HeuristicsResult update_heuristics(oop o, bool allow_rebias) {
markOop mark = o->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->blueprint();
jlong cur_time = os::javaTimeMillis();
//獲取上次執行bulk revication的時間 jlong last_bulk_revocation_time = k->last_biased_lock_bulk_revocation_time();
//獲取執行bulk revocation的次數 int revocation_count = k->biased_lock_revocation_count();
//定義在globs.hpp,BiasedLockingBulkRebiasThreshold取值為20;BiasedLockingBulkRevokeThreshold取值為40,BiasedLockingDecayTime為25000毫秒
if ((revocation_count >= BiasedLockingBulkRebiasThreshold) &&
(revocation_count < BiasedLockingBulkRevokeThreshold) &&
(last_bulk_revocation_time != 0) &&
(cur_time - last_bulk_revocation_time >= BiasedLockingDecayTime)) {
// This is the first revocation we've seen in a while of an
// object of this type since the last time we performed a bulk
// rebiasing operation. The application is allocating objects in
// bulk which are biased toward a thread and then handing them
// off to another thread. We can cope with this allocation
// pattern via the bulk rebiasing mechanism so we reset the
// klass's revocation count rather than allow it to increase
// monotonically. If we see the need to perform another bulk
// rebias operation later, we will, and if subsequently we see
// many more revocation operations in a short period of time we
// will completely disable biasing for this type.
//在執行了一定時間之內,執行的撤銷次數沒有超過閾值,那麼認為可以優先執行bulk rebias,因此將計數迴歸原始值
k->set_biased_lock_revocation_count(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) {
//達到執行bulk revoke的閾值,執行bulk revoke return HR_BULK_REVOKE;
}
if (revocation_count == BiasedLockingBulkRebiasThreshold) {
//達到 bulk rebias的閾值,執行bulk rebias
return HR_BULK_REBIAS;
}
//預設執行單次的撤銷
return HR_SINGLE_REVOKE;
}
bulk_revoke_or_rebias_at_safepoint
bulk revoke的關鍵在於它會遍歷所有執行緒棧的每一幀
static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,
bool bulk_rebias,
bool attempt_rebias_of_object,
JavaThread* requesting_thread) {
…
if (bulk_rebias) {
...
// Now walk all threads' stacks and adjust epochs of any biased
// and locked objects of this data type we encounter
//遍歷所有的執行緒
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
//遍歷執行緒棧的每一幀,獲取所有的監視器
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()) {
// We might have encountered this object already in the case of recursive locking
assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment");
//更新所有棧中的有偏向鎖的epoch
owner->set_mark(mark->set_bias_epoch(cur_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);
}
…
if (attempt_rebias_of_object &&
o->mark()->has_bias_pattern() &&
klass->prototype_header()->has_bias_pattern()) {
//bias_epoch本身則是表示獲取了偏向鎖
markOop new_mark = markOopDesc::encode(requesting_thread, o->mark()->age(),
klass->prototype_header()->bias_epoch());
o->set_mark(new_mark);
//執行rebiase
status_code = BiasedLocking::BIAS_REVOKED_AND_REBIASED;
...
}
}
revoke_bias的執行如下
static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread) {
markOop mark = obj->mark();
…
//偏向鎖的頭
markOop biased_prototype = markOopDesc::biased_locking_prototype()->set_age(age);
//非偏向鎖的頭
markOop unbiased_prototype = markOopDesc::prototype()->set_age(age);
…
//獲取偏向的執行緒
JavaThread* biased_thread = mark->biased_locker();
if (biased_thread == NULL) {
// Object is anonymously biased. We can get here if, for
// example, we revoke the bias due to an identity hash code
// being computed for an object.
if (!allow_rebias) {
//沒有執行緒獲取,又需要執行rebias,改掉物件頭即可
obj->set_mark(unbiased_prototype);
}
...
//撤銷完畢
return BiasedLocking::BIAS_REVOKED;
}
…
//執行緒活著
//遍歷棧幀,獲取所有這個執行緒的監視器,按照最年輕到最老的順序
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(biased_thread);
BasicLock* highest_lock = NULL;
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
if (mon_info->owner() == obj) {
...
// Assume recursive case and fix up highest lock later
//當前棧幀存在了這個物件的鎖
markOop mark = markOopDesc::encode((BasicLock*) NULL);
highest_lock = mon_info->lock();
//更新棧中的mark為NULL
highest_lock->set_displaced_header(mark);
}
...
}
}
if (highest_lock != NULL) {
// Fix up highest lock to contain displaced header and point
// object at it
//將最久的那個lock更新為沒有偏向 ,棧中 設定了鎖記錄
highest_lock->set_displaced_header(unbiased_prototype);
// Reset object header to point to displaced mark
//將物件頭指向棧中的位置,這樣表示就沒有偏向了
obj->set_mark(markOopDesc::encode(highest_lock));
assert(!obj->mark()->has_bias_pattern(), "illegal mark state: stack lock used bias bit");
...
} else {
...
if (allow_rebias) {
obj->set_mark(biased_prototype);
} else {
// Store the unlocked value into the object's header.
obj->set_mark(unbiased_prototype);
}
}
//撤銷完畢 return BiasedLocking::BIAS_REVOKED;
}