前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java锁膨胀过程中的解惑:1.单线程不一定能获取偏向锁 ; 2.安全点重偏向不能直接占有仍有效偏向锁

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

作者头像
执生
发布2020-11-11 17:27:38
6370
发布2020-11-11 17:27:38
举报
文章被收录于专栏:立权的博客

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()

就不会成立。

代码语言:javascript
复制
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;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-11-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档