• Java 锁(synchronized)升级过程


    java中的锁是针对对象而言的,它锁住的是一个对象,并且具有可重入的性质。
    java中的对象内存结构如图所示
    普通对象内存结构:

    java普通对象结构
    数组对象内存结构:
    java数组对象
    其中关于锁状态的记录主要存储在_mark(markword)中,markword的结构如下以64位为例:
    markword
    最开始的synchronized的实现是直接启用重量级锁,这样对于效率的影响是比较大,在后来的改进中引入了锁升级的概念,来增加执行的效率

     public synchronized void testSync() {
            synchronized(this){
            System.out.println("test");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这个synchronized锁住的是包含当前方法的对象,当一个线程(Thread_1)来调用这个方法的时候,就可能会触发锁升级的过程,如下图所示:
    在这里插入图片描述
    自旋锁也叫轻量级锁,一般通过cas算法实现。
    注意:锁只会升级不会降级
    1、当Thread-1访问对象的时候,首先通过cas操作去获取偏向锁并将锁的偏向位更改为1;
    2、当另一个线程(thread-2)到达的时候会比较自身线程id和对象头中id是否一致,发现不一致就会去检测对象头中的线程是否存活,如果Thread-1还是存活的就升级为轻量级锁;
    3、如果获取失败则说明存在竞争关系,这时候将偏向锁升级为轻量级锁;升级为轻量级锁之后会在thread-2线程的栈帧中开辟一块锁记录空间叫做displaced Mark Word,并将锁对象的markword拷贝到线程本身的displaced Mark Word空间中,然后通过cas的方式去设置锁对像中线程id指针,并将锁的标志设置为00;
    4、当其中一个线程的自旋次数超过阈值(默认是10)的时候为了防止cpu空转,会将自旋锁升级为重量级锁,将对象监视器的指针存储在对象头之中。

    对象监视器结构如图
    // hotspot中的对象监视器
    ObjectMonitor() {
    _count = 0; //用来记录该对象被线程获取锁的次数
    _waiters = 0;
    _recursions = 0; //锁的重入次数
    _owner = NULL; //指向持有ObjectMonitor对象的线程
    _WaitSet = NULL; //处于wait状态的线程,会被加入到_WaitSet
    _WaitSetLock = 0 ;
    _EntryList = NULL ; //处于等待锁block状态的线程,会被加入到该列表
    }
    在升级为重量级锁之后会创建一个ObjectMonitor()对象,并在锁对象的markword中记录下objectMonitor的指针;
    在ObjectMonitor中有两个队列(entryList waitSet)和一个指针(owner),两个队列可以称为锁池和等待池,指针中记录的是当前拥有锁的线程;

  • 相关阅读:
    ABP集成SqlSugar
    ROS 工作空间
    小程序源码:网课查题微信小程序源码下载,题库资源丰富自动采集,支持语音拍照识别-多玩法安装简单
    使用Mybatis自定义插件实现不侵入业务的公共参数自动追加
    webpack5基础--02_基本配置( 5 大核心概念)
    Spring Cloud Alibaba整合Seata实战
    ubuntu20.04安装pip
    通过 js 给元素添加动画样式animation属性 ,以及 perspective 属性探究
    OceanBase学习笔记之分区与索引
    8-汇编-寄存器(CPU工作原理)03
  • 原文地址:https://blog.csdn.net/zjshuster/article/details/132806297