触发批量重偏向的条件,可以参考这篇文章 源码解析-触发批量撤销或批量重偏向的条件。
批量重偏向源码 在这里。
摘出其中批量重偏向的逻辑:
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;
if (bulk_rebias) {
// 第一部分:批量重偏向。。。。。。。。。。。。。。。。。。。。。。。。。。。。
// 类开启了偏向模式,才进行批量重偏向
if (klass->prototype_header()->has_bias_pattern()) {
int prev_epoch = klass->prototype_header()->bias_epoch();
// 自增类的 epoch
klass->set_prototype_header(klass->prototype_header()->incr_bias_epoch());
// 获取类自增后的 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()) {
// 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 与 类的 epoch 保持一致
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 {
// 批量撤销的逻辑
...
}
...
BiasedLocking::Condition status_code = BiasedLocking::BIAS_REVOKED;
// 第三部分:如果满足条件,则直接将锁重偏向于当前线程。。。。。。。。。。。。。。。。
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); // 由于是在安全点里,所以不需要 CAS 操作
status_code = BiasedLocking::BIAS_REVOKED_AND_REBIASED;
...
}
}
...
return status_code;
}
上面整个与批量重偏向有关的逻辑可以分为三个部分:
一、批量重偏向
批量重偏向在这里做的逻辑是:
- 自增类的 epoch。
- 更新所有该类正在被持有的偏向锁的 epoch。
由于后面线程请求偏向锁时,如果发现锁对象的 epoch 不等于 类的 epoch,则认为该偏向锁的偏向已经过期,可以把该偏向锁看成是匿名偏向锁使用。
所以第 2 点工作也是为了保证正在持有该类偏向锁的线程其同步语义不被破坏。
二、当前偏向锁的撤销
当前偏向锁的撤销逻辑,由 revoke_bias 方法完成。关于 revoke_bias 方法,可以参考:源码解析-偏向锁撤销流程解读
当前偏向锁的撤销结果,也与进行批量重偏向时方法的参数 attempt_rebias_of_object 有关。
因为如果 revoke_bias 的第二个参数为 true,则可以把偏向锁撤销为匿名偏向。
所以当前偏向锁的撤销有三种可能:
如果偏向锁正在被其所有者持有,那一定是撤销为其所有者的轻量级锁。
而如果偏向锁没有正在被其所有者持有,则根据 revoke_bias 的第二个参数决定撤销为匿名偏向还是无锁。
三、当前锁的重偏向
如果当前偏向锁的撤销结果是匿名偏向的话,会在方法最后的逻辑中直接将锁偏向于当前线程。
网友评论