> 文章列表 > 一遍讲清楚:偏向锁到轻量级锁的升级过程(为什么耗资源)

一遍讲清楚:偏向锁到轻量级锁的升级过程(为什么耗资源)

一遍讲清楚:偏向锁到轻量级锁的升级过程(为什么耗资源)

目录

上原理:

细说原理:

什么是锁记录呢?

什么是Mark Word 呢?

上图解:


上原理:

偏向锁使⽤了⼀种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时, 持有偏向锁的线程才会释放锁偏向锁升级成轻量级锁时,会暂停拥有偏向锁的线程,重置偏向锁标识,这个过程看起来容易,实则开销还是很⼤的,⼤概的过程如下:

  1.  在⼀个安全点(在这个时间点上没有字节码正在执⾏)停⽌拥有锁的线程。
  2.  遍历线程栈,如果存在锁记录的话,需要修复锁记录和Mark Word,使其变成⽆锁状态。
  3.  唤醒被停⽌的线程,将当前锁升级成轻量级锁。

所以,如果应⽤程序⾥所有的锁通常出于竞争状态,那么偏向锁就会是⼀种累赘,对于这种情况,我们可以⼀开始就把偏向锁这个默认功能给关闭:

-XX:UseBiasedLocking=false

细说原理:

问题:在偏向锁状态下,如果有其他线程竞争同一个对象的锁,那么偏向锁就需要升级成轻量级锁。此时,JVM会唤醒竞争的线程,让它们重新尝试获取锁 意思是:先有一个锁B竞争偏向锁A,然后阻塞掉这个锁B,再然后升级A锁为轻量级锁 重新唤醒锁B继续竞争一次吗?

答:

错误!在偏向锁状态下,如果有其他线程竞争同一个对象的锁,JVM会撤销偏向锁并将对象状态升级为轻量级锁,然后唤醒竞争的线程,让它们去竞争锁。具体的过程如下:

  1. 偏向锁的持有者线程被挂起,阻止它继续执行。
  2. JVM遍历线程栈,找到持有偏向锁的线程,并检查它的锁记录是否存在。如果存在,则需要清空该锁记录,并更新对象头的Mark Word。(如果锁记录存在,JVM需要清空该锁记录,并更新对象头的Mark Word,将其标记为无锁状态。这样做的目的是为了避免原持有锁的线程通过之前的锁记录再次获取锁。)
  3. JVM将对象头的Mark Word 更新为指向锁记录的指针,表示对象状态已经变为轻量级锁。
  4. JVM唤醒持有偏向锁的线程,让它重新执行。此时,它会尝试获取对象的锁,但会发现对象已经不再是偏向锁状态,于是会转而竞争锁。(感觉被抛弃了)
  5. 如果其他线程也在竞争同一个对象的锁,则它们会按照轻量级锁的竞争规则去竞争锁,而不是偏向锁的竞争规则。

因此,不是先让锁B竞争偏向锁A,然后阻塞锁B,再升级A锁为轻量级锁,再重新唤醒锁B。而是在撤销偏向锁的同时,就会唤醒所有竞争锁的线程,让它们重新竞争锁。

什么是锁记录呢?

当对象状态为偏向锁时, Mark Word 存储的是偏向的线程ID;
当状态为轻量级锁时, Mark Word 存储的是指向线程栈中 Lock Record 的指针;
当状态为重量级锁时, Mark Word 为指向堆中的monitor对象的指针。

什么是Mark Word 呢?

可以看这个:java对象头 MarkWord_markword 对象头_烟雨星空的博客-CSDN博客

上图解:

上图表示:在偏向锁状态下,如果有其他线程竞争同一个对象的锁,那么偏向锁就需要升级成轻量级锁,这就是从竞争到撤销偏向锁的一个过程。

平阳教育网