从 class 文件 看 synchronize 锁膨胀过程(偏向锁 轻量级锁 自旋锁 重量级锁)
大家好,我是烤鸭:
前几天看马士兵老师的并发的课,里边讲到了 synchronize 锁的膨胀过程,今天想用代码演示一下。
1. 简单介绍
关于synchronize jdk 1.5 以后的优化,由重量级锁调整为膨胀过程。分别是 偏向锁 轻量级锁(自旋锁) 重量级锁。
2. 用例编写
pom文件增加 jol的包,用于看对象头的信息。
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.10</version>
</dependency>
下面的注释已经写的挺清楚的了,关于锁几种状态的转换。
SyncSourceTest.java
package src.source;import org.openjdk.jol.info.ClassLayout;/*** Created by test on 2020/5/10*/
public class SyncSourceTest {static Object noLock;static Object biaseLock;static Object lightLock;static Object heavyLock;public static void main(String[] args) throws InterruptedException {noLock = new Object();// 无锁状态,由于print 方法是synchronize 修饰,其实打印语句就已经是加偏向锁了(如果满足下面的偏向锁条件)System.out.print("线程["+Thread.currentThread().getName()+"]:无锁状态对象布局:"+ClassLayout.parseInstance(noLock).toPrintable());// 偏向锁,由于JVM 默认偏向锁4s后开启,可以线程sleep.5 或者设置VM参数关闭延迟 -XX:BiasedLockingStartupDelay=0Thread.sleep(5000L);biaseLock = new Object();System.out.println("线程["+Thread.currentThread().getName()+"]:偏向锁状态对象布局:"+ClassLayout.parseInstance(biaseLock).toPrintable());// 轻量级锁,由于轻量级锁是偏向锁升级的,需要先给对象一个偏向锁,如果不加偏向锁,只有一个线程加锁变成偏向锁lightLock = new Object();synchronized (lightLock) {System.out.println("线程["+Thread.currentThread().getName()+"]:[轻量级锁提前加偏向锁]轻量级锁状态对象布局:"+ClassLayout.parseInstance(lightLock).toPrintable());}synLight();// 重量级锁heavyLock = new Object();synHeavy();}public static void synLight() throws InterruptedException {for (int i = 0; i < 1; i++) {getLightLock();}}public static void getLightLock() {new Thread(() -> {try {synchronized (lightLock){System.out.println("线程["+Thread.currentThread().getName()+"]:轻量级锁状态对象布局:"+ClassLayout.parseInstance(lightLock).toPrintable());}} catch (Exception e) {e.printStackTrace();}}).start();}public static void synHeavy() throws InterruptedException {for (int i = 0; i < 2; i++) {getHeavyLock();}}private static void getHeavyLock() {new Thread(() -> {try {synchronized (heavyLock){System.out.println("线程["+Thread.currentThread().getName()+"]:重量级锁状态对象布局:"+ClassLayout.parseInstance(heavyLock).toPrintable());}} catch (Exception e) {e.printStackTrace();}}).start();}
}
关于对象布局,我们就先不研究了,这里重点说一下 对象头。
线程[main]:无锁状态对象布局:java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
线程[main]:偏向锁状态对象布局:java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total线程[main]:[轻量级锁提前加偏向锁]轻量级锁状态对象布局:java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 28 e3 02 (00000101 00101000 11100011 00000010) (48441349)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total线程[Thread-2]:重量级锁状态对象布局:java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) ba ee 0d 26 (10111010 11101110 00001101 00100110) (638447290)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total线程[Thread-0]:轻量级锁状态对象布局:java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 88 f5 a4 29 (10001000 11110101 10100100 00101001) (698676616)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total线程[Thread-1]:重量级锁状态对象布局:java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) ba ee 0d 26 (10111010 11101110 00001101 00100110) (638447290)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes totalProcess finished with exit code 0
可以看出 无锁状态下各个状态下 mark word 后三位的值:
无锁:001
偏向:101
轻量级锁:000
重量级锁:010
本来想写一下,关于 轻量级锁 当前线程栈帧中 lock record 和 mark word的变化,无奈查了很多资料不知道在哪可以看到 lock record,有的说是显式或者隐式地创建lock record 空间,咱也不清楚了。更多关于轻量级锁的源码看这篇吧。
https://blog.csdn.net/z69183787/article/details/104502540?utm_source=app
3. 编译class文件
看下面的class文件,顺便说一下jvm的字节码指令。
可以看下 class文件里边对象的变化:
7: putstatic #3 // Field noLock:Ljava/lang/Object; 静态变量 初始化时
39: getstatic #3 // Field noLock:Ljava/lang/Object; 获取 静态变量
而到了偏向锁对象初始化之前,线程 睡眠了5秒。
57: ldc2_w #16 // long 5000l ,5000入栈
60: invokestatic #18 // Method java/lang/Thread.sleep:(J)V , 执行 sleep
135: monitorenter 对应的这行代码 :synchronized (lightLock)
184: monitorexit 加锁结束
190: monitorexit 后面又有一次 加锁结束
原因是 线程内部加锁后,调用 print 方法,又加了一次锁(重入锁),所以需要释放两次。
D:\gitee\rep\leetcode-gradle\src\main\java\src\source> javac -classpath ".;D:\dev\repository\org\openjdk\jol\jol-core\0.10\jol-core-0.10.jar" -encoding UTF-8 .\SyncSourceTest.javaD:\gitee\rep\leetcode-gradle\src\main\java\src\source> javap -c .\SyncSourceTest.class
Compiled from "SyncSourceTest.java"
public class src.source.SyncSourceTest {static java.lang.Object noLock;static java.lang.Object biaseLock;static java.lang.Object lightLock;static java.lang.Object heavyLock;public src.source.SyncSourceTest();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]) throws java.lang.InterruptedException;Code:0: new #2 // class java/lang/Object3: dup4: invokespecial #1 // Method java/lang/Object."<init>":()V7: putstatic #3 // Field noLock:Ljava/lang/Object;10: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;13: new #5 // class java/lang/StringBuilder16: dup17: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V20: ldc #7 // String 线程[22: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;25: invokestatic #9 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;28: invokevirtual #10 // Method java/lang/Thread.getName:()Ljava/lang/String;31: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;34: ldc #11 // String ]:无锁状态对象布局:36: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;39: getstatic #3 // Field noLock:Ljava/lang/Object;42: invokestatic #12 // Method org/openjdk/jol/info/ClassLayout.parseInstance:(Ljava/lang/Object;)Lorg/openjdk/jol/info/ClassLayout;45: invokevirtual #13 // Method org/openjdk/jol/info/ClassLayout.toPrintable:()Ljava/lang/String;48: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;51: invokevirtual #14 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;54: invokevirtual #15 // Method java/io/PrintStream.print:(Ljava/lang/String;)V57: ldc2_w #16 // long 5000l60: invokestatic #18 // Method java/lang/Thread.sleep:(J)V63: new #2 // class java/lang/Object66: dup67: invokespecial #1 // Method java/lang/Object."<init>":()V70: putstatic #19 // Field biaseLock:Ljava/lang/Object;73: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;76: new #5 // class java/lang/StringBuilder79: dup80: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V83: ldc #7 // String 线程[85: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;88: invokestatic #9 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;91: invokevirtual #10 // Method java/lang/Thread.getName:()Ljava/lang/String;94: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;97: ldc #20 // String ]:偏向锁状态对象布局:99: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;102: getstatic #19 // Field biaseLock:Ljava/lang/Object;105: invokestatic #12 // Method org/openjdk/jol/info/ClassLayout.parseInstance:(Ljava/lang/Object;)Lorg/openjdk/jol/info/ClassLayout;108: invokevirtual #13 // Method org/openjdk/jol/info/ClassLayout.toPrintable:()Ljava/lang/String;111: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;114: invokevirtual #14 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;117: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V120: new #2 // class java/lang/Object123: dup124: invokespecial #1 // Method java/lang/Object."<init>":()V127: putstatic #22 // Field lightLock:Ljava/lang/Object;130: getstatic #22 // Field lightLock:Ljava/lang/Object;133: dup134: astore_1135: monitorenter136: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;139: new #5 // class java/lang/StringBuilder142: dup143: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V146: ldc #7 // String 线程[148: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;151: invokestatic #9 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;154: invokevirtual #10 // Method java/lang/Thread.getName:()Ljava/lang/String;157: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;160: ldc #23 // String ]:[轻量级锁提前加偏向锁]轻量级锁状态对象布局:162: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;165: getstatic #22 // Field lightLock:Ljava/lang/Object;168: invokestatic #12 // Method org/openjdk/jol/info/ClassLayout.parseInstance:(Ljava/lang/Object;)Lorg/openjdk/jol/info/ClassLayout;171: invokevirtual #13 // Method org/openjdk/jol/info/ClassLayout.toPrintable:()Ljava/lang/String;174: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;177: invokevirtual #14 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;180: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V183: aload_1184: monitorexit185: goto 193188: astore_2189: aload_1190: monitorexit191: aload_2192: athrow193: invokestatic #24 // Method synLight:()V196: new #2 // class java/lang/Object199: dup200: invokespecial #1 // Method java/lang/Object."<init>":()V203: putstatic #25 // Field heavyLock:Ljava/lang/Object;206: invokestatic #26 // Method synHeavy:()V209: returnException table:from to target type136 185 188 any188 191 188 anypublic static void synLight() throws java.lang.InterruptedException;Code:0: iconst_01: istore_02: iload_03: iconst_14: if_icmpge 167: invokestatic #27 // Method getLightLock:()V10: iinc 0, 113: goto 216: returnpublic static void getLightLock();Code:0: new #28 // class java/lang/Thread3: dup4: invokedynamic #29, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;9: invokespecial #30 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V12: invokevirtual #31 // Method java/lang/Thread.start:()V15: returnpublic static void synHeavy() throws java.lang.InterruptedException;Code:0: iconst_01: istore_02: iload_03: iconst_24: if_icmpge 167: invokestatic #32 // Method getHeavyLock:()V10: iinc 0, 113: goto 216: return
}
4. 总结
有很多文章对 synchronize 分析过,我这里只是想使用代码演示一下各种场景,很多地方并没有深入到源码和原理层面。
简单来说,就是:
无锁:mark word 记录 hashcode和分代年龄。
单线程加锁(偏向锁),mark word 记录线程id。
偏向锁升级到 轻量级锁,mark word 值 替换为 当前线程栈中的lock record 的指针。
轻量级锁到重量级锁:mark word 值 重量级锁 的指针。
其中自旋锁是 轻量级锁到重量级锁 发生的:
从 class 文件 看 synchronize 锁膨胀过程(偏向锁 轻量级锁 自旋锁 重量级锁)相关推荐
- 12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
小陈:呼叫老王...... 老王:来了来了,小陈你准备好了吗?今天我们来讲synchronized的锁重入.锁优化.和锁升级的原理 小陈:早就准备好了,我现在都等不及了 老王:那就好,那我们废话不多说 ...
- 带你彻底搞懂锁膨胀,偏向锁,轻量级锁,重量级锁
1.synchronized 我们都知道synchronized内部有四种状态,分别是:无锁.偏向锁.轻量级锁和重量级锁,所以要搞懂这几种锁之间的变化我们得对synchronized有个大致的了解. ...
- (JUC)图文并茂!!!! 超详细 偏向锁VS轻量级锁VS重量级锁VS自旋
偏向锁,轻量级锁,重量级锁 前言 java对象内存布局 (1)重量级锁(Moniter) (2)轻量级锁 锁膨胀.自旋.自适应自旋 (3)偏向锁(以64位虚拟机为例) 2.偏向锁撤销的3种情况 (1) ...
- synchronized的偏向锁、轻量级锁和重量级锁
文章目录 Java对象头 偏向锁 批量重偏向 批量撤销 轻量级锁 重量级锁 Monitor 原理 Java对象头 普通对象 Mark Word在64 位虚拟机中的结构为 Mark Word后三(两)位 ...
- 十二、偏向锁、轻量级锁、重量级锁,锁的膨胀过程
1.对象的状态有几种: 无锁.偏向锁.轻量级锁.重量级锁.GC标记,共5个状态 2.锁的膨胀过程 无锁:程序多线程执行过程中没有去执行synchronized修饰区域或者方法. 偏向锁:发生在程序单线 ...
- 锁升级过程(偏向锁/轻量级锁/重量级锁)
锁的前置知识 如果想要透彻的理解java锁的来龙去脉,需要先了解锁的基础知识:锁的类型.java线程阻塞的代价.Markword. 锁的类型 锁从宏观上分类,分为悲观锁与乐观锁. 乐观锁 乐观锁是一种 ...
- Synchronize的底层优化(CAS,重量级锁,轻量级锁,偏向锁)
Synchronize的底层优化(CAS,重量级锁,轻量级锁,偏向锁) Java 对象头 (重点) 对象头 对象头包含两部分: 运行时元数据(Mark Word)和类型指针(Klass Word) 运 ...
- Java如何避免重量级锁,Java 中锁是如何一步步膨胀的(偏向锁、轻量级锁、重量级锁)...
文章目录 重量级锁(Mutex Lock) 偏向锁(比较 ThreadID) 偏向锁获取过程 偏向锁的释放 轻量级锁(自旋) 轻量级锁的加锁过程 轻量级锁的释放 总结 重量级锁(Mutex Lock) ...
- 谈谈JVM内部锁升级过程
简介: 对象在内存中的内存布局是什么样的?如何描述synchronized和ReentrantLock的底层实现和重入的底层原理?为什么AQS底层是CAS+volatile?锁的四种状态和锁升级过程应 ...
最新文章
- javax.xml.ws.webserviceexception class do not have a property of the name
- Maven构建Struts2框架的注意事项
- Math工具类常用API使用案例
- jq中查找上级_云计算自动化运维之linux-工作中常用命令总结(上)
- 新手AS常见问题集锦
- [LeetCode]119.Pascal#39;s Triangle II
- 怎么看电脑电源多少w_UPS不间断电源设备哪个品牌好?如何选购家用电脑UPS电源?UPS电源价格多少?...
- 大数据之-Hadoop3.x_MapReduce_切片源码分析---大数据之hadoop3.x工作笔记0104
- 网易编程题-操作序列
- CS API 测试3
- 网络节点是计算机与网络的什么,网络节点是什么意思?
- java运行 .class文件_运行java的class文件方法详解
- 微型计算机原理实验二,微型计算机原理与接口技术实验指导(第2版)
- Java 分布式解决方案
- MBA-day16 数学-应用题-集合问题-公式
- 缠论中第49课:没必要参与操作级别及以上级别的下跌与超过操作级别的盘整,如何理解与应用?
- php20以内的勾股数,[求助]编程求100以内的所有勾股数
- ip解析经纬度,基站定位经纬度,用就完事了
- weblogic与oracle断开,菜鸟经验:oracle与weblogic自动启动与停止
- jsBlob数据转为图片