Java锁膨胀过程中的解惑:1.单线程不一定能获取偏向锁 ; 2.安全点重偏向不能直接占有仍有效偏向锁

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; }

 

posted @ 2020-11-05 22:37  执生  阅读(446)  评论(0编辑  收藏  举报