1.偏向锁的获取逻辑主要在汇编实现的 biased_locking_enter 方法中
请求线程进入这个方法之后,会直接判断锁依赖对象的对象头是否有 偏向锁 成分(101是偏向锁成分)。
如果没有,直接跳出,退出后直接尝试把自己栈上的BiasLock 地址写入对象头,写入成功的前提是锁依赖对象没加锁(001是没加锁)
这样的话,岂不是所有未加锁对象,进入biased_locking_enter都会退出,直接设置轻量级锁成功?
那么开启轻量级锁有什么用呢?
问题在于,如果锁依赖对象的 Klass 的 prototype_header 中的 后几位是 101 ,也就是偏向锁成分。
那么这个 Klass 的对象在创建的时候,都会直接把后几位设置成 101,但是没有写入 JavaThread* ,也就是匿名偏向锁(anonymous bias_lock)
所以会在 biased_locking_enter 获得偏向锁成功。
2.在 revoke_and_rebais 的最后,当 撤销偏向锁到达了一定频率,则会触发 请求线程使用 VM_Thread::execute 提交 VM_BulkRevokeBias 这个 operation 给VM_Thread 执行
需要注意的是 VM_BulkRevokeBias 这个 Operation 是直接继承自 VM_Operation 的,调用evaluate_concurrently时
默认使用VM_Operation的虚函数,默认返回 false,也就是 VM_Thread::execute 提交 Operation 请求以后会阻塞在提交点。
VM_BulkRevokeBias 会在安全点(所有Operation都是在安全点执行的)调用bulk_revoke_or_rebias_at_safepoint
这个函数 和 revoke_and_rebias 是膨胀过程中 唯二能返回 BIAS_REVOKED_AND_REBIASED 状态的函数
返回这个状态表示锁依赖对象的对象头中的 JavaThread* 被置为当前线程的 JavaThread* 了。也就是当前线程获取偏向锁成功。也就是重偏向成功。
但是有一个疑问,在函数的末尾貌似没有判断 对象头的 epoch 是否有效,直接就把自己的JavaThread*写进去了,我很是不解。
虽然末尾要在 bulk_rebias 为 true ,attempt_rebias_of_object 都为 true 才会执行。
但是 bulk_rebias 在 update_heuristics 调用较为频繁(revoke_and_rebias较为频繁,也就是偏向锁撤销较为频繁)的时候会 就会为true
attempt_rebias_of_object 在 faster_enter 处被决定,通过 synchronized 进入 faster_enter 时,会是 true
所以这两个值不难成立,为什么就能直接获得偏向锁呢?现在的线程可还在synchronized块里。
但是实际上,我忽略了 bulk_rebias 为 true,会进入的分支里 ,会调用 revoke_bias。
revoke_bias 在偏向锁被其他线程占有的时候,会直接把偏向锁膨胀成轻量级锁。
这样的话,对象头的 偏向成分就会消失(101是偏向成分,bias_pattern),这样的话,末尾的 o->mark()->has_bias_pattern()
就不会成立。
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->blueprint()->set_last_biased_lock_bulk_revocation_time(cur_time);
klassOop k_o = o->klass();
Klass* klass = Klass::cast(k_o);
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();
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()) {
assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment");
owner->set_mark(mark->set_bias_epoch(cur_epoch));
}
}
}
}
// 被忽略的分支
revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread);
} else {
klass->set_prototype_header(markOopDesc::prototype());
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()) {
revoke_bias(owner, false, true, requesting_thread);
}
}
}
revoke_bias(o, false, true, requesting_thread);
}
BiasedLocking::Condition status_code = BiasedLocking::BIAS_REVOKED;
//末尾 bulk_rebias 为 true ,attempt_rebias_of_object 都为 true 才会执行
if (attempt_rebias_of_object &&
o->mark()->has_bias_pattern() &&
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;
}return status_code;
}