美文网首页
JVM锁升级过程分析

JVM锁升级过程分析

作者: cbhe | 来源:发表于2020-05-27 17:05 被阅读0次

    过程概括

    1. 从未被获取过得锁:无锁状态
    2. 只被一个线程获取的锁:偏向锁
    3. 多个线程获取锁,但并没法生锁等待:轻量级锁
    4. 多个线程出现锁竞争:重量级锁(也就是一般意义的锁)

    举个栗子

    你家有一个碗,当没有人用这个碗时,它处于无锁状态。当你用这个碗吃饭时,它进入偏向锁状态,以后每次你用这个碗吃饭的话,你都不用进行加锁和解锁操作。有一天你女朋友去你家,但她只要求你吃完了再把碗给她用,你们虽然共用这一个碗,但是并不会在同一时间用,这是碗就进入了轻量级锁。但当你正在用碗吃饭的时候,你女朋友说她也饿了,要抢你的碗,这时候,你只能给碗加上重量级锁,才能避免你女朋友直接来抢你的失误。

    锁升级的数据结构

    HotSpot虚拟机将每个对象的加锁信息和当前状态存储在对象头的mark word字段,结构如下:


    图1 HotSpot虚拟机对象头Mark Word格式

    HotSpot虚拟机的对象头分为两部分,第一部分用于存储对象自身的运行时数据,如HashCode、GC分代年龄等。这部分数据在32位和64位的java虚拟机中分别占用32位和64位,官方称之为Mark World。这部分时实现轻量级锁和偏向锁的关键。另一部分用于存储指向方法区对象类型数据的指针,如果是数组对象,还会有额外的部分用于存储数组的长度。

    锁升级过程

    • 无锁 → 偏向锁
      如果一块临界区从未被任何线程访问过,则它就一直处于无锁状态。当第一个线程来访问它时,这时候线程会判断锁状态标志位为01偏向标志位为0,表示无锁且可以使用偏向锁。这时就会启动加偏向锁的过程:

        1. 将偏向标志位设置为1
        1. 使用CAS操作将线程ID写入对象头

      如果cas操作成功,则该线程就获取到了偏向锁,该线程每次进入同步块时就再也不用加锁解锁了。

    • 偏向锁 → 轻量级锁
      当第二个线程尝试获取已被置为偏向的锁时,偏向模式就马上宣告结束。根据锁对象目前是否处于被锁定的状态来决定是否撤销偏向(偏向标志设为0),撤销后锁标志位恢复到未锁定或轻量级锁的状态。如果对象处于锁定状态,则直接将锁升级到重量级锁,否则由当前试图访问到线程加上轻量级锁。轻量级锁的加锁过程如下:

      • 将锁标志位设置为00,表示轻量级锁
      • 在当前线程的栈帧中开辟一片空间存储Mark World
      • 通过CAS操作将对象头的信息替换为栈帧中存储备份的地址
    • 轻量级锁 → 重量级锁
      如果出现两个以上的线程争用同一个锁的情况,那轻量级锁就不再有效,必须要膨胀为重量级锁,锁标志位状态改为10,此时Mark World中存储的就是指向重量级锁的指针,后面等待锁的线程也不许进入阻塞状态。

    相关文章

      网友评论

          本文标题:JVM锁升级过程分析

          本文链接:https://www.haomeiwen.com/subject/ldvyahtx.html