synchronized锁升级过程

一、synchronized锁加到什么地方

       synchronized 上锁,其实锁信息是加在对象头中的 markdown,对象中的前四个字节表示markdown;markdown还记录了对象的gc、hashcode 信息

      注意:markdown 结构与jvm虚拟机的实现有关,

      I)32位Hotspot虚拟机markdown结构如下:

synchronized锁升级过程_第1张图片

      II)64位Hotspot 虚拟机的markdown结构如下:

synchronized锁升级过程_第2张图片

二、synchronized 锁升级的过程

       synchronized 锁升级其实就是markword 后几位锁标志位变化的过程

synchronized锁升级过程_第3张图片

         当new 出一个对象时会有2种情况:普通对象(主线)和 匿名偏向

         当new 出一个普通对象,一旦给普通对象加上关键字synchronized,synchronized 锁

         会升级为偏向锁(),

         当锁竞争加大(轻度竞争),偏向锁会升级为轻量级锁(也叫自旋锁或无锁)

         当竞争超过一定时间还没获取锁,轻量级锁就会升级成重量级锁

        

     锁状态:

          在markdown 中最低3位表示synchronized 锁的状态,优先看最低的2位,

          下边是markdown锁标志位与锁的对应关系

偏向锁标志位 锁标志位2 锁标志位1
轻量级锁,自旋锁,无锁 0 0
重量级锁 1 0
GC标志位(用于垃圾回收) 1 1
偏向锁 1 0 1
无锁态(刚刚new出对象) 0 0 1

三、用户空间锁 VS 重量级锁

      偏向锁 、轻量级锁都是用户空间完成的,又称为用户锁,用户锁不用向cpu内核申请锁;

      重量级锁是需要向操作系统内核(即CPU)申请锁

      什么是偏向锁?

           对很多synchronized 的方法或代码块,很多时候是在线程环境中执行的,没有竞争,

           这就没必要每次执行synchronized方法都向CPU内核申请加锁;当第一个线程调

           用 synchronized方法时,只需要把该线程的id设置到markdown 中就行了,这就是偏向锁;

      什么是轻量级锁(自旋锁,无锁)?

            有多个线程竞争synchronized锁时,先把偏向锁撤销,通过自旋的竞争(自旋锁)升级

            到轻量级锁;

            竞争过程:

                 每个线程的线程栈中都会生成一个LR(LockRecord 锁记录),然后通过自旋争抢

                 的方式,尽可能的把自身的LR设置到 markdown中,若设置成功,makrdown会有

                 一个指针指向LR,表示该线程持有了synchronized;竞争失败的线程会在用户空间

                 通过CAS的方式(自旋)继续竞争

       什么是重量级锁?

               重量级锁markdown 记录的是一个 ObjectMointor 对象;

               ObjectMointor 是jvm提供的一个用于向操作系统OS申请锁的工具,由C++实现

               

四、synchronized 锁重入

       synchronized 是可以重入的锁

       可重入锁必须要记录重入次数,因为重入几次后边就要释放几次

        偏向锁的重入次数记录在线程栈中,每重入一次 LockRecord 就要加1,

         偏向锁每重入一次,在线程栈中都会生成一个LR,但这个LR的值等于NULL,重入次数

         记录在最底层(即第一个LR)LR中;每释放一次锁,线程栈中都要弹出一个LR,当

        线程栈中的LR全部弹出,表示锁全部释放

        轻量级锁重入次数与偏向锁差不多,锁重入次数都是记录在线程栈的LR重,每重入一次也是

       生成一个LR;

        重量级锁的重入次数记录在ObjectMointor 对象中

五、轻量级锁(自旋锁)什么时候升级为重量级锁?

        有线程超过10次自旋,或者自旋线程数超过cpu核数的一半;

        可以通过jvm参数 -XX:PreBlockSpin 来控制自旋次数,jdk1.6之后不需要手动调整自旋次数

        jdk1.6之后加入了自适应自旋 Adapative Self Spinning,由jvm自己控制

       升级重量级锁:向操作系统申请资源,linux mutex,CPU从3级-0级系统调用,线程

       挂起,进入等待队列等待系统调度,然后再映射会用户空间

六、什么有自旋锁了还需要重量级锁?

       要明白一点,自旋是需要消耗cpu资源的,若持有锁的线程业务耗时过长或自旋的线程

       比较多,这样会消耗大量的cpu资源;

       重量级锁有等待队列,所有拿不到锁的线程会被放入等待队列中,不需要消耗cpu资源

七、什么叫偏向锁启动和偏向锁未启动?

        偏向锁是否一定比自旋锁效率高?

                不一定,偏向锁只有在单线程环境中效率最高;多线程环境下偏向锁不一定比自旋锁

                效率高;明确知道多线程情况下没必要使用偏向锁,因为多线程环境下偏向锁一定涉及

               锁撤销,这就额外增加了cpu消耗,此时应该关闭偏向锁,直接使用自旋算性能可能更高

          jvm启动过程中,明确知道会有很多线程争抢,所以启东时默认不打开偏向锁,启东完成

          后再打开偏向锁,即延时打开偏向锁

          -XX:BiasedLockingStartupDelay  用来设置偏向锁延时

你可能感兴趣的:(java,jvm,开发语言)