Java并发之彻底搞懂偏向锁升级为轻量级锁

https://blog.csdn.net/fycghy0803/article/details/74910238

 网上有许多讲偏向锁,轻量级锁的文章,但对偏向锁如何升级讲的不够明白,有些文章还相互矛盾,经过对jvm源码(biasedLocking.cpp)的仔细分析和追踪,基本升级过程有了一个清晰的过程,现将升级流程阐述如下:

     因为偏向锁,锁住对象时,会写入对象头相应的标识,我们先把对象头(官方叫法为:Mark Word)的图示如下(借用了网友的图片):

      

    通过上面的图片,我们可以知道,对象处于偏向锁时,mark word中的偏向锁标记为1,锁标志位为01;下面是分析过jvm源码(biasedLocking.cpp)解析的偏向锁升级流程(忽略一些细节),示例中:线程1当前拥有偏向锁对象,线程2是需要竞争到偏向锁。

 

  1. 线程2来竞争锁对象;
  2. 判断当前对象头是否是偏向锁;
  3. 判断拥有偏向锁的线程1是否还存在;
  4. 线程1不存在,直接设置偏向锁标识为0(线程1执行完毕后,不会主动去释放偏向锁);
  5. 使用cas替换偏向锁线程ID为线程2,锁不升级,仍为偏向锁;
  6. 线程1仍然存在,暂停线程1;
  7. 设置锁标志位为00(变为轻量级锁),偏向锁为0;
  8. 从线程1的空闲monitor record中读取一条,放至线程1的当前monitor record中;
  9. 更新mark word,将mark word指向线程1中monitor record的指针;
  10. 继续执行线程1的代码;
  11. 锁升级为轻量级锁;   
  12. 线程2自旋来获取锁对象;

   上面仍有一个问题,即如何判断线程1已经不存在了?

        仍然是分析完jvm源码(thread.cpp)后,得到的如下结论:

           (1) 线程执行start时,会将自己写入一个thread_list中,这是一个linked结构,有pre和next节点;

                        对应源码位置:

                               void Threads::add(JavaThread* p, bool force_daemon) {

  // The threads lock must be owned at this point

  assert_locked_or_safepoint(Threads_lock);

  // See the comment for this method in thread.hpp for its purpose and

  // why it is called here.

  p->initialize_queues();

  p->set_next(_thread_list);

  _thread_list = p;

  _number_of_threads++;

  oop threadObj = p->threadObj();

  bool daemon = true;

  // Bootstrapping problem: threadObj can be null for initial

  // JavaThread (or for threads attached via JNI)

  if ((!force_daemon) && (threadObj == NULL || !java_lang_Thread::is_daemon(threadObj))) {

        _number_of_non_daemon_threads++;

        daemon = false;

  }

 

  p->set_safepoint_visible(true);

  ThreadService::add_thread(p, daemon);

    // Possible GC point.
  Events::log(p, "Thread added: " INTPTR_FORMAT, p);

   }

           (2)线程执行完后,会将自己从thread list中清理掉(源码位置: Threads::remove(this));

       因此只需判断thread list中是否存在线程1即可,判断源代码(位于biasedLocking.cpp中 )如下:

             bool thread_is_alive = false;

 if (requesting_thread == biased_thread) {

       thread_is_alive = true;

 } else {

     for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) {

              if (cur_thread == biased_thread) {

                    thread_is_alive = true;

                    break;

              }

 

          }

 }

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值