分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程

1. 对象内部结构

一个对象内部结构由对象头、实例成员以及对齐填充组成。其中对象头由64位的Mark Word以及元数据指针和数组长度(只有数组对象才有)组成,其中元数据指针指向的是元空间中该对象的类.class。其中Mark Word包括一位偏向状态和两位锁状态标志,如下图。

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第1张图片

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第2张图片

 

2. 内部结构查看

2.1 jor-core插件下载

首先,我们去maven仓库下载一个jol-core插件或者在pom.xml中配置一下依赖,我这边使用的是IDEA2020版,所以下载了2020年的一个版本,如下图。

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第3张图片

 

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第4张图片

 

2.2 对象内部结构分析

2.2.1 不是数组对象,而且有填充补齐位。填充补齐位为了凑成8个字节,64位,方便64位系统寻址。

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第5张图片

2.2.2 不是数组对象,且没有填充补齐位

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第6张图片

2.2.3 数组对象

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第7张图片

 

3. 锁升级或降级过程的锁标志位

3.1 偏向锁的启用和延时

3.1.1 偏向锁是否启用,可通过-XX:+UseBiasedLocking开启偏向锁以及-XX:-UseBiasedLocking关闭偏向锁;偏向锁启动延时时间,可通过-XX:BiasedLockingStartupDealy变量设置时间,ms为单位。通过 java -XX:+PrintFlagsFinal -version | findstr "BiasedLocking" 可查看java关于偏向锁的默认设置,如下图。

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第8张图片

3.1.2 启动偏向锁,并设定偏向锁启动延迟时间为4s,如下图。

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第9张图片

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第10张图片

3.2 偏向锁升级、膨胀过程(本节操作都是在开启偏向锁,而且延时为0的场景下)

3.2.1 升级为偏向锁,高位的三位锁标志是101(带线程id);释放锁不会降级。

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第11张图片

3.2.2 升级为轻量级锁,高位的锁标志是两位00。如果抢锁的线程和对象头内偏向锁记录的线程不一致时,升级为轻量级锁;

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第12张图片

注意,其它博客提到的这么一句话:如果偏向锁的那个偏向线程不存在,锁不升级。经过实践,仍然还是升级为轻量级锁了!!!

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第13张图片

3.2.3 再次抢锁时,直接从无锁状态变为轻量级锁,然后释放锁又降级为无锁状态

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第14张图片

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第15张图片

3.2.4 只要两个线程同时争抢,那么线程直接就升级为重量级锁,不管原先是什么锁状态;而且释放锁后,也不会降级。

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第16张图片

这边需要提一下Lock Record,每一个线程在抢锁时,都会先在线程的栈帧中创建存储Lock Record的空间(存储共享对象的Mark Word的拷贝);然后每个线程抢锁时都会尝试将共享对象的Mark Word指向自己的Lock Record。最终,共享对象的Mark Word会存储抢锁成功线程的Lock Record地址;那些抢锁失败的线程会CAS自旋一定次数,如果在指定次数内成功了(默认10次),那么就更改共享对象的Mark Word;如果指定次数后仍不成功,就将锁升级为重量级锁了。

 

附录

最终出现了一个问题,系统开启偏向锁,两个线程间隔100ms抢锁后都是偏向锁,第二个线程抢锁没有升级为轻量级锁;而且两次对象头内容都一样,为什么???

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第17张图片

当两个线程抢锁的时间间隔改为20ms,锁升级变化过程又正常了。

分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程_第18张图片

你可能感兴趣的:(Java,对象结构分析及对象头说明,锁升级和降级过程)