当前位置: 首页 > news >正文

JVM对象头中的锁信息机制详解

JVM对象头中的锁信息机制详解

Java中的对象锁机制是高性能并发的基石,而这一切的底层实现都离不开对象头中的 Mark Word 字段。本文将系统梳理JVM对象头中锁信息的存储与演化机制,解析锁升级与批量重偏向优化原理,并通过JOL工具实战验证对象头的实际变化。


一、对象头与Mark Word结构

每个Java对象在内存中的布局如下(64位JVM,开启指针压缩):

字段大小说明
Mark Word64 bits存储锁信息、哈希码、GC年龄等
Klass Pointer32 bits指向类元数据
Array Length32 bits仅数组对象,记录长度

Mark Word的动态结构

Mark Word 的内容根据锁状态动态变化,主要分为以下几种:

状态标志位存储内容(64位)适用场景
无锁01哈希码31bit、GC年龄4bit、未用位、偏向位无竞争
偏向锁01线程ID54bit、epoch2bit、GC年龄4bit、偏向位单线程独占
轻量级锁00指向栈中锁记录的指针62bit低并发、短同步块
重量级锁10指向Monitor(OS互斥量)指针62bit高并发、长耗时临界区
GC标记11空值,用于GC标记GC期间

二、锁状态的升级与降级机制

JVM采用不可逆锁升级策略,根据竞争强度动态提升锁级别,避免频繁的锁降级带来的性能问题。

首次线程访问
其他线程竞争
自旋失败
批量重偏向
批量撤销
锁释放无竞争
锁释放
无锁
偏向锁
轻量级锁
重量级锁

各锁状态简析

  • 偏向锁:第一次线程访问时,Mark Word“贴标签”记录线程ID,后续该线程进入同步块无需CAS,极致优化无竞争场景。
  • 轻量级锁:当有第二个线程竞争时,通过CAS将Mark Word复制到线程栈中的锁记录(Lock Record),自旋尝试获取锁。
  • 重量级锁:自旋失败或竞争激烈时,升级为重量级锁,对象头指向Monitor,线程进入阻塞队列,由操作系统调度。

锁升级示例

public class Counter {private int count = 0;private final Object lock = new Object();public void increment() {synchronized(lock) {count++;}}public static void main(String[] args) {Counter counter = new Counter();// 1. 单线程独占(偏向锁)IntStream.range(0, 100).forEach(i -> counter.increment());// 2. 两线程交替访问(轻量级锁)new Thread(() -> IntStream.range(0, 100).forEach(i -> counter.increment())).start();new Thread(() -> IntStream.range(0, 100).forEach(i -> counter.increment())).start();// 3. 多线程竞争(重量级锁)ExecutorService pool = Executors.newFixedThreadPool(10);IntStream.range(0, 1000).forEach(i -> pool.submit(counter::increment));}
}

三、偏向锁批量重偏向机制(epoch优化)

1. 触发条件

  • 某个类的对象被不同线程撤销偏向锁超过阈值(默认20次,可用 -XX:BiasedLockingBulkRebiasThreshold 调整)。
  • 达到更高阈值(默认40次,-XX:BiasedLockingBulkRevokeThreshold)后,彻底禁用该类偏向锁

2. epoch机制实现

  • 每个类维护一个全局epoch值,对象头Mark Word中记录当前epoch副本。
  • 发生批量重偏向时,类的epoch+1,无需遍历对象头一一CAS,只需访问时对比epoch。
  • 访问对象时,若对象头epoch与类epoch不一致,则允许重新偏向新线程。
示例代码
public class BulkRebiasDemo {public static void main(String[] args) {List<Object> list = new ArrayList<>();// 阶段1:A线程创建并偏向100个对象for (int i = 0; i < 100; i++) {Object obj = new Object();synchronized(obj) {} // 偏向线程Alist.add(obj);}// 阶段2:B线程访问这些对象new Thread(() -> {for (Object obj : list) {synchronized(obj) {// 前20次撤销,后续批量重偏向}}}).start();}
}

3. 优势

  • 批量操作:O(N)次CAS变为O(1)全局epoch更新,大幅降低锁撤销开销。
  • 性能提升:高并发下减少CPU颠簸,提升吞吐量。

四、JVM对象头结构与验证

1. JOL工具实战

JOL (Java Object Layout) 可直接查看对象头布局:

Maven依赖:

<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.17</version>
</dependency>

验证代码:

public static void main(String[] args) {Object obj = new Object();System.out.println(ClassLayout.parseInstance(obj).toPrintable());int[] arr = new int[3];System.out.println(ClassLayout.parseInstance(arr).toPrintable());
}

输出示例(64位JVM,压缩指针):

java.lang.Object object internals:OFFSET  SIZE   TYPE DESCRIPTION0     4        (object header)    # Mark Word4     4        (object header)    # 类型指针8     4        (object header)    # 数组长度(数组对象)12     4        (loss due to...)[I object internals:OFFSET  SIZE   TYPE DESCRIPTION0     4        (object header)    # Mark Word4     4        (object header)    # 类型指针8     4        (object header)    # 数组长度=312    12    int [I.<elements>      # 数组元素24     4        (loss due to...)

2. 锁状态变化观测

Object lock = new Object();
System.out.println("初始状态:" + ClassLayout.parseInstance(lock).toPrintable());synchronized(lock) {System.out.println("加锁状态:" + ClassLayout.parseInstance(lock).toPrintable());
}
  • 关注Mark Word最后2~3位:01(无锁/偏向锁)、00(轻量级锁)、10(重量级锁)

五、性能影响与优化建议

锁类型适用场景性能特点优化建议
偏向锁单线程独占零额外开销-XX:BiasedLockingStartupDelay=0
轻量级锁低并发短同步块自旋消耗CPU控制自旋次数(-XX:PreBlockSpin)
重量级锁高并发/长临界区上下文切换开销大减少同步块粒度
批量重偏向高并发多线程访问O(1)批量优化,减少CAS合理设置阈值,避免频繁撤销

六、总结

  • 对象头中的Mark Word是Java对象锁实现的核心,能够动态存储锁状态、线程ID、指针等信息。
  • 锁升级不可逆,保证了线程安全和性能的平衡。
  • 批量重偏向机制通过epoch优化,将大量CAS操作降为常数级epoch对比,极大提升高并发下的锁撤销效率。
  • 借助JOL工具,开发者可直观观测对象头在不同锁状态下的变化,为并发调优提供有力支撑。

理解JVM对象头中的锁机制,有助于我们写出更高效、更具可预测性的并发代码。欢迎大家用JOL实战,深度探索Java对象的“内在世界”!


参考资料:

  • Java官方JVM文档
  • JOL项目主页
  • 深入理解Java虚拟机

相关文章:

  • Linux 软件包|服务管理
  • ESP32开发入门(九):HTTP服务器开发实践
  • 请求参数:Header 参数,Body 参数,Path 参数,Query 参数分别是什么意思,什么样的,分别通过哪个注解获取其中的信息
  • 【Leetcode】系列之206反转链表
  • 需求变更控制不严,如何防止项目范围扩大
  • Express知识框架
  • Day22打卡-复习
  • PHP编写图书信息爬虫程序
  • 跨域问题深度解析与解决方案
  • rbac模型详解
  • Go语言多线程爬虫与代理IP反爬
  • 【Java继承】——面向对象编程的基石
  • 从经典力扣题发掘DFS与记忆化搜索的本质 -从矩阵最长递增路径入手 一步步探究dfs思维优化与编程深度思考
  • 互联网大厂Java求职面试实战:Spring Boot与微服务场景深度解析
  • 鸿蒙HarmonyOS list优化一: list 结合 lazyforeach用法
  • yarn workspace使用指南
  • 精品可编辑PPT | 全面风险管理信息系统项目建设风控一体化标准方案
  • 数据库实验报告 SQL SERVER 2008的基本操作 1
  • 企业对数据集成工具的需求及 ETL 工具工作原理详解
  • 一键生成达梦、Oracle、MySQL 数据库 ER 图!解锁高效数据库设计!
  • 莆田高端模板建站/有广告位怎么找广告商
  • 朝阳网站建设 国展/营销战略有哪些内容
  • 深圳住建网站/百度服务电话
  • 企业网站怎么做的/关键词优化靠谱推荐
  • 国内对企业网站开发的研究/免费的网络营销方式
  • 新疆住房和建设厅网站/seo网站排名软件