并发基石-Markword与锁升级 迈不过友情╰ 2022-02-28 17:24 151阅读 0赞 ### 并发基石-Markword与锁升级 ### * * synchronized * 对象头Markword * 偏向锁、轻量级锁、重量级锁介绍 * * 偏向锁与无锁 * 锁升级-轻量级锁 * 锁升级-重量级锁 * 代码验证 ## synchronized ## synchronized关键字是java提供的互斥锁关键字,我们常说的互斥锁一般都是非自旋锁,即竞争不到锁的线程会进入阻塞状态知道被唤醒 今天我们来讲讲java中用来对synchronized进行优化的三种锁,同时会介绍markword对象头 目前我在网上搜到的十几篇博客讲的都有问题,可能有写对的我没搜到. 很多人不经过验证直接把markOop.hpp中的JavaThread\*当成ThreadId这是错误的,实际是java线程在C语言的指针 并且未计算过hashCode和计算过hashCode的情况也是不一样的 本篇博客最后会展示使用jol工具,读取展示对象头的结果进行验证 附上openjdk的markOop.hpp[链接][Link 1] ## 对象头Markword ## 对象头是java将对象比较常用和重要的运行时数据,如hashCode、gc标识、存活年龄等等进行集中存储的一组数据 占据8个字节,以下只讨论目前比较常见的64位的情况 ## 偏向锁、轻量级锁、重量级锁介绍 ## 64bit下各锁状态的Markword格式 64 bits: -------- unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object) JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object) PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object) size:64 ----------------------------------------------------->| (CMS free block) unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object) JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object) narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object) unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block) [ptr | 00] locked ptr points to real header on stack [header | 0 | 01] unlocked regular object header [ptr | 10] monitor inflated lock (header is wapped out) [ptr | 11] marked used by markSweep to mark an object 32bit下各锁状态的Markword格式 32 bits: -------- hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object) JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object) size:32 ------------------------------------------>| (CMS free block) PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object) 也就是对象头的最后两位,是作为锁的状态标志 00—轻量锁 01—偏向锁/无锁 10—重量锁 11—GC标记 偏向锁状态和无锁状态通过区分对象头倒数第三位来确定,0代表无锁,1代表偏向锁 注意,未计算hashCode的对象的初始状态为匿名偏向锁(线程指针为0,代表无线程获取)而非无锁 ### 偏向锁与无锁 ### java中对于锁的实际获取依赖于UnSafe调用native方法去实现不同操作系统上的cas原语操作 如果一个对象,在每次作业的运行始终处于单一线程,那每次对于锁的检测、获取和释放都会对性能造成不小的消耗 于是java引入了偏向锁 当一个处于匿名偏向锁状态的对象,第一次被一个线程竞争时,其对象头会被标记为偏向锁,同时存储其线程指针 接下来每次该线程对该锁的获取都不需要经过不必要的cas判断锁资源从而优化了性能,这也是偏向的由来 匿名偏向锁状态的对象如果计算了hashCode,则会变为无锁状态。hashCode存在markword,并且接下来不会再进去偏向锁 匿名偏向锁状态的对象被获取时,进入非匿名偏向锁状态,markword存储持有者的java线程在操作系统的C语言指针 无锁状态下的对象被获取时,会直接跳到轻量级锁(因为偏向锁下markword没有记录hashCode,没办法存储hashCode,而轻量级锁的下面讲) 非匿名偏向锁状态的对象计算了hashCode以后,会直接进入重量级锁,此时的重量级锁会(重量级锁的下面讲) 开启偏向锁的支持需要添加两个虚拟机参数 -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 第一个参数是开启偏向锁 第二个参数是指定立即开启,因为默认偏向锁的开启时在虚拟机运行后延时5秒 如果没有线程竞争,非匿名偏向锁偏向锁释放后会变回匿名偏向锁状态 ### 锁升级-轻量级锁 ### 当一个对象处于非匿名偏向锁状态下,如果有别的线程过来竞争,另一个线程尝试竞争锁,竞争失败并给予jvm一个竞争的信号以后进入自旋(不断尝试获取锁) 接下来在持有该锁的线程执行来到安全点时,会触发stop the world并将膨胀为轻量级锁 轻量级锁会创建一份锁记录(Lock Record)在当前持有他的线程的线程栈里 LockRecord中包含一个owner属性指向锁对象,而锁对象的markword中也会保存一个执行该LockRecord的指针 这时的竞争就是轻量级锁的竞争了,轻量级锁的竞争时,竞争锁的线程会在一个周期时间内不断的自旋获取锁,如果获取失败就会进入阻塞并将markword的锁标记标记为10(重量级锁) 因为LockRecord复制了markword,所以在执行同步块时并不去关注markword,只有到了释放时 1.锁对象的markword升级为了重量级锁,将锁对象升级为重量级锁,锁对象的markword存储一个指向一个由操作系统实现的mutex互斥变量,唤醒阻塞的竞争线程 2.markword没变化,释放锁,对象锁恢复到无锁状态(如果LockRecord记录的是偏向锁,则恢复到匿名偏向锁,否则恢复到无锁状态) ## 锁升级-重量级锁 ## 当对象来到重量级锁以后,新被从竞争队列挑选出来一部分竞争锁的线程队列会一起竞争锁 最终竞争到锁的一个线程会继续运行,竞争失败的线程进入阻塞队列 处于执行状态的线程执行完同步代码块后,会释放锁并唤醒阻塞队列中的线程 将他们加入新的挑选出来的竞争锁的线程队列,并重新竞争锁,重复以上操作 因为需要阻塞和唤醒线程,所以需要从用户态到系统态切换,所以重量级锁下的系统开销很大 ## 代码验证 ## Thread currentThread = Thread.currentThread(); System.out.println("threadId : "+Long.toBinaryString(currentThread.getId())); Object o = new Object(); System.out.println("-------------------------------------------------------------------------------------------------------"); System.out.println("init object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("-------------------------------------------------------------------------------------------------------"); synchronized (o) { System.out.println("synchronized lock object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("synchronized finished"); System.out.println("-------------------------------------------------------------------------------------------------------"); } Thread.sleep(2000); System.out.println("after synchronized object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("binary hashCode : "+Integer.toBinaryString(o.hashCode())); System.out.println("-------------------------------------------------------------------------------------------------------"); System.out.println("after calculate hashcode object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("-------------------------------------------------------------------------------------------------------"); synchronized (o) { System.out.println("synchronized lock object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("synchronized finished"); System.out.println("-------------------------------------------------------------------------------------------------------"); } Object o2 = new Object(); System.out.println("o2 hashCode : "+Long.toBinaryString(o2.hashCode())); System.out.println("init lock object2 info"); System.out.println(ClassLayout.parseInstance(o2).toPrintable()); System.out.println("-------------------------------------------------------------------------------------------------------"); synchronized (o2) { System.out.println("synchronized lock object2 info"); System.out.println(ClassLayout.parseInstance(o2).toPrintable()); System.out.println("synchronized finished"); System.out.println("-------------------------------------------------------------------------------------------------------"); } System.out.println("after lock object2 info"); System.out.println(ClassLayout.parseInstance(o2).toPrintable()); System.out.println("-------------------------------------------------------------------------------------------------------"); //计算过hashcode的会直接进入轻量锁 输出结果 threadId : 1 ------------------------------------------------------------------------------------------------------- init object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 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 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ------------------------------------------------------------------------------------------------------- synchronized lock object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 e8 09 01 (00000101 11101000 00001001 00000001) (17426437) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total synchronized finished ------------------------------------------------------------------------------------------------------- after synchronized object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 e8 09 01 (00000101 11101000 00001001 00000001) (17426437) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total binary hashCode : 100000111110100010001111000001 ------------------------------------------------------------------------------------------------------- after calculate hashcode object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 c1 23 fa (00000001 11000001 00100011 11111010) (-98320127) 4 4 (object header) 20 00 00 00 (00100000 00000000 00000000 00000000) (32) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ------------------------------------------------------------------------------------------------------- synchronized lock object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 50 f7 c4 02 (01010000 11110111 11000100 00000010) (46462800) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total synchronized finished ------------------------------------------------------------------------------------------------------- o2 hashCode : 110101100000011100010111110011 init lock object2 info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 f3 c5 81 (00000001 11110011 11000101 10000001) (-2117733631) 4 4 (object header) 35 00 00 00 (00110101 00000000 00000000 00000000) (53) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ------------------------------------------------------------------------------------------------------- synchronized lock object2 info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 50 f7 c4 02 (01010000 11110111 11000100 00000010) (46462800) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total synchronized finished ------------------------------------------------------------------------------------------------------- after lock object2 info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 f3 c5 81 (00000001 11110011 11000101 10000001) (-2117733631) 4 4 (object header) 35 00 00 00 (00110101 00000000 00000000 00000000) (53) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 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 currentThread = Thread.currentThread(); System.out.println("threadId : "+Long.toBinaryString(currentThread.getId())); Object o = new Object(); System.out.println("-------------------------------------------------------------------------------------------------------"); System.out.println("init object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("-------------------------------------------------------------------------------------------------------"); new Thread() { public void run() { synchronized (o) { System.out.println("-------------------------------------------------------------------------------------------------------"); System.out.println("-------------------------------------------------------------------------------------------------------"); System.out.println("another thread id "+Long.toBinaryString(this.getId())); System.out.println("synchronized lock object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("synchronized finished"); System.out.println("-------------------------------------------------------------------------------------------------------"); System.out.println("------------------------------------------------------------------------------------------------------"); } } }.start(); synchronized (o) { System.out.println("synchronized lock object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); //有锁未计算hashCode状态下计算hashCode o.hashCode(); System.out.println("when synchronized calculate hashcode "); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("synchronized finished"); System.out.println("-------------------------------------------------------------------------------------------------------"); } Thread.sleep(2000); System.out.println("after synchronized object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("binary hashCode : "+Integer.toBinaryString(o.hashCode())); System.out.println("-------------------------------------------------------------------------------------------------------"); System.out.println("after calculate hashcode object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("-------------------------------------------------------------------------------------------------------"); synchronized (o) { System.out.println("synchronized lock object info"); System.out.println(ClassLayout.parseInstance(o).toPrintable()); System.out.println("synchronized finished"); System.out.println("-------------------------------------------------------------------------------------------------------"); } Object o2 = new Object(); System.out.println("o2 hashCode : "+Long.toBinaryString(o2.hashCode())); System.out.println("init lock object2 info"); System.out.println(ClassLayout.parseInstance(o2).toPrintable()); System.out.println("-------------------------------------------------------------------------------------------------------"); synchronized (o2) { System.out.println("synchronized lock object2 info"); System.out.println(ClassLayout.parseInstance(o2).toPrintable()); System.out.println("synchronized finished"); System.out.println("-------------------------------------------------------------------------------------------------------"); } System.out.println("after lock object2 info"); System.out.println(ClassLayout.parseInstance(o2).toPrintable()); System.out.println("-------------------------------------------------------------------------------------------------------"); //计算过hashcode的会直接进入轻量锁 输出结果 threadId : 1 ------------------------------------------------------------------------------------------------------- init object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 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 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ------------------------------------------------------------------------------------------------------- synchronized lock object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) ba c4 c4 02 (10111010 11000100 11000100 00000010) (46449850) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total when synchronized calculate hashcode java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) ba c4 c4 02 (10111010 11000100 11000100 00000010) (46449850) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total synchronized finished ------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------- another thread id 1010 synchronized lock object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) ba c4 c4 02 (10111010 11000100 11000100 00000010) (46449850) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total synchronized finished ------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------ after synchronized object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 c1 23 fa (00000001 11000001 00100011 11111010) (-98320127) 4 4 (object header) 20 00 00 00 (00100000 00000000 00000000 00000000) (32) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total binary hashCode : 100000111110100010001111000001 ------------------------------------------------------------------------------------------------------- after calculate hashcode object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 c1 23 fa (00000001 11000001 00100011 11111010) (-98320127) 4 4 (object header) 20 00 00 00 (00100000 00000000 00000000 00000000) (32) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ------------------------------------------------------------------------------------------------------- synchronized lock object info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 90 f5 ad 02 (10010000 11110101 10101101 00000010) (44955024) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total synchronized finished ------------------------------------------------------------------------------------------------------- o2 hashCode : 110101100000011100010111110011 init lock object2 info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 f3 c5 81 (00000001 11110011 11000101 10000001) (-2117733631) 4 4 (object header) 35 00 00 00 (00110101 00000000 00000000 00000000) (53) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ------------------------------------------------------------------------------------------------------- synchronized lock object2 info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 90 f5 ad 02 (10010000 11110101 10101101 00000010) (44955024) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total synchronized finished ------------------------------------------------------------------------------------------------------- after lock object2 info java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 f3 c5 81 (00000001 11110011 11000101 10000001) (-2117733631) 4 4 (object header) 35 00 00 00 (00110101 00000000 00000000 00000000) (53) 8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ------------------------------------------------------------------------------------------------------- 更多文章,请搜索公众号歪歪梯Club ![更多资料,请搜索公众号编程宝可梦][20200521183346518.jpg] [Link 1]: http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/oops/markOop.hpp [20200521183346518.jpg]: /images/20220227/4c67e76c072f4198bdc1cd2218f0e8ee.png
相关 Java并发编程中的锁升级问题 在Java的并发编程中,锁升级(Lock Involvement)是一个需要注意的问题。通常在多线程环境中,有以下几种类型的锁: 1. `synchronized`块/方法: Love The Way You Lie/ 2024年09月11日 21:36/ 0 赞/ 18 阅读
相关 面试~Synchronized 与 锁升级 讲讲 Synchronized/ 讲讲 Synchronized 锁升级 内部实现 Markword synchronized在修饰方法和代码块在字节码上 「爱情、让人受尽委屈。」/ 2024年04月06日 13:44/ 0 赞/ 33 阅读
相关 并发编程基石:管程 大家好,我是易安! 如果有人问我学习并发并发编程,最核心的技术点是什么,我一定会告诉他,管程技术。Java语言在1.5之前,提供的唯一的并发原语就是管程,而且1.5之后提供的 ゝ一世哀愁。/ 2024年03月22日 10:44/ 0 赞/ 38 阅读
相关 Java并发编程之 锁升级过程 阅读本文档前需了解的前置知识: 1. 进程和线程的概念 2. 并发和并行的概念 3. 创建线程的三种方式 4. 线程常见方法 5. 线程的五种状态及其转换 sy 阳光穿透心脏的1/2处/ 2022年11月09日 15:29/ 0 赞/ 161 阅读
相关 mysql 与sqlserver的锁升级 锁可谓RDBMS中最复杂、最神秘的技术。[锁升级(Lock Escalation)][Lock Escalation]是指将当前锁的粒度降低(有点Java锁粗化的味道),是一种 分手后的思念是犯贱/ 2022年10月02日 10:46/ 0 赞/ 128 阅读
相关 并发基石-AQS与Condition 并发基石-AQS与Condition Condition AQS Node 执行开始 妖狐艹你老母/ 2022年02月28日 17:26/ 0 赞/ 203 阅读
相关 并发基石-Markword与锁升级 并发基石-Markword与锁升级 synchronized 对象头Markword 偏向锁、轻量级锁、重量级锁介绍 迈不过友情╰/ 2022年02月28日 17:24/ 0 赞/ 152 阅读
相关 锁升级 前言: 本文的原文在[这里][Link 1],这个兄弟真心觉得挺厉害的,他的博客看过来,真的是从菜鸟到高手,向他学习,当然这个兄弟也是参考老外的文章,在[这里][Link 2 缺乏、安全感/ 2021年12月15日 07:41/ 0 赞/ 260 阅读
相关 偏向锁升级、批量重偏向&撤销、Java对象头、Markword构成等 批量重偏向和批量撤销理解:[https://blog.csdn.net/qq\_33553218/article/details/107699356][https_blog.c 矫情吗;*/ 2021年09月07日 06:09/ 0 赞/ 298 阅读
还没有评论,来说两句吧...