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

JVM 锁自动升级机制详解

JVM 锁自动升级机制详解

JVM 中的锁升级是指 synchronized 锁从无锁状态逐步升级到重量级锁的过程,这是 Java 并发性能优化的核心机制之一。Java 8 的 ConcurrentHashMap 使用的 synchronized 正是受益于这套自动升级机制。

1. 锁升级的四个阶段

JVM 锁状态按照竞争程度从低到高分为:

  1. 无锁状态 (Unlocked)
  2. 偏向锁 (Biased Locking)
  3. 轻量级锁 (Lightweight Locking)
  4. 重量级锁 (Heavyweight Locking)
[无锁] → [偏向锁] → [轻量级锁] → [重量级锁]

2. 各阶段详细机制

2.1 偏向锁 (Biased Locking)

适用场景:没有实际竞争或只有单线程访问

实现原理

  • 在对象头 Mark Word 中记录偏向线程ID
  • 后续进入时只需检查线程ID是否匹配
  • 不涉及 CAS 操作和操作系统互斥

升级触发条件

  • 另一个线程尝试获取锁(产生竞争)

优势

  • 完全无同步开销(仅第一次有开销)
  • 适合 ConcurrentHashMap 的单桶无竞争情况

2.2 轻量级锁 (Thin Lock)

适用场景:低竞争、短时间同步

实现原理

  1. 在栈帧中建立锁记录(Lock Record)
  2. 使用 CAS 将对象头 Mark Word 替换为指向锁记录的指针
    cmpxchg  // CAS指令
    
  3. 成功则获取锁,失败则膨胀为重量级锁

升级触发条件

  • CAS 操作失败(表示有竞争)
  • 自旋超过阈值(默认10次,JVM可调节)

优势

  • 避免直接进入重量级锁
  • 在用户态完成同步(无需内核介入)

2.3 重量级锁 (Heavyweight Lock)

适用场景:高竞争场景

实现原理

  • 通过操作系统的互斥量(mutex)实现
  • 未获取锁的线程进入等待队列
  • 涉及用户态到内核态的切换

特点

  • 性能开销大(约100ns级延迟)
  • 保证公平性和可靠性

3. 锁升级全过程示例

以 ConcurrentHashMap 的桶锁为例:

synchronized(bucketHead) {  // 桶头节点作为锁对象// 同步代码块
}
  1. 首次进入

    • 启用偏向锁,记录当前线程ID到对象头
  2. 同一线程再次进入

    • 检查线程ID匹配,直接执行(零开销)
  3. 第二个线程进入

    • 撤销偏向锁
    • 升级为轻量级锁(CAS竞争)
  4. CAS竞争失败

    • 自旋重试(自适应自旋)
    • 自旋失败后升级重量级锁

4. 关键技术实现

4.1 对象头结构

|---------------------------------------------------|
| Mark Word (64 bits)                               |
|---------------------------------------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 |
|---------------------------------------------------|
  • biased_lock:偏向锁标志
  • lock:锁状态标志
    • 00:轻量级锁
    • 01:无锁/偏向锁
    • 10:重量级锁
    • 11:GC标记

4.2 升级过程关键代码(HotSpot 实现)

// 偏向锁撤销
void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, TRAPS) {if (UseBiasedLocking) {BiasedLocking::revoke(obj, THREAD);}slow_enter(obj, lock, THREAD);
}// 轻量级锁获取
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {markOop mark = obj->mark();if (mark->is_neutral()) {  // 无锁状态lock->set_displaced_header(mark);if (mark == obj()->cas_set_mark(markOopDesc::INFLATING(), mark)) {// 膨胀为重量级锁ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);}}
}

5. 性能影响与优化

5.1 各阶段典型耗时

锁阶段耗时特点
偏向锁~1-2ns仅第一次有开销
轻量级锁~5-10nsCAS操作开销
重量级锁~100ns+系统调用/上下文切换

5.2 JVM 调优参数

  1. 关闭偏向锁(高竞争场景):
    -XX:-UseBiasedLocking
    
  2. 调整自旋次数:
    -XX:PreBlockSpin=10
    
  3. 启用自适应性自旋:
    -XX:+UseSpinning
    

6. 在 ConcurrentHashMap 中的应用

  1. 理想情况

    • 多数桶无竞争 → 保持偏向锁状态
    • 读操作完全无锁
  2. 中等竞争

    • 少量线程操作同一桶 → 轻量级锁
    • 通过CAS快速解决冲突
  3. 高竞争

    • 热点桶出现 → 升级重量级锁
    • 但仅限于单个桶不影响其他桶操作

7. 现代JVM的优化趋势

  1. 锁消除 (Lock Elision):

    • 逃逸分析确定对象不会逃逸时,直接消除锁
  2. 锁粗化 (Lock Coarsening):

    • 合并相邻的同步块减少锁开销
  3. 自适应自旋

    • 根据历史成功率动态调整自旋时间

这种自动升级机制使得:

  • 无竞争时达到近乎无锁的性能
  • 低竞争时保持高效
  • 高竞争时保证正确性
  • 完美适配 ConcurrentHashMap 的桶锁需求
http://www.xdnf.cn/news/1114885.html

相关文章:

  • 【AI论文】GLM-4.1V-Thinking:迈向具备可扩展强化学习的通用多模态推理
  • Java面试基础:面向对象(2)
  • 数学与应用数学核心课程有哪些?全文解析!
  • 【webrtc】gcc当前可用码率2:设置阈值通知码率改变
  • 梯度下降算法:像下山一样找到最优解
  • Linux驱动开发1:设备驱动模块加载与卸载
  • ControlNet与T2IAdapter
  • 三种网络类型
  • WordPress Ads-pro 本地文件包含漏洞复现(CVE-2025-4380)
  • 设计模式之工厂模式:对象创建的智慧之道
  • 从“被动巡检”到“主动预警”:塔能物联运维平台重构路灯管理模式
  • Docker安装Nginx
  • Leaflet面试题及答案(61-80)
  • 全国青少年信息素养大赛-算法创意实践挑战赛小学组复赛(代码版)
  • Gin框架统一响应与中间件机制学习笔记
  • JAVA-springboot 整合Activemq
  • Docker一键安装中间件(RocketMq、Nginx、MySql、Minio、Jenkins、Redis)脚步
  • jeepay开源项目开发中金支付如何像其他支付渠道对接那样简单集成,集成服务商模式,极简集成工具。
  • HarmonyOS-ArkUI Web控件基础铺垫1-HTTP协议-数据包内容
  • Docker三剑客
  • AWS Lambda Container 方式部署 Flask 应用并通过 API Gateway 提供访问
  • 手写std::optional:告别空指针的痛苦
  • 系规备考论文:论IT服务知识管理
  • 010_学习资源与社区支持
  • C语言基础教程(002):变量介绍
  • Spring Boot 配置注解处理器 - spring-boot-configuration-processor
  • 初识计算机网络
  • Node.js 聊天内容加密解密实战教程(含缓存密钥优化)
  • python 列表(List) vs. 元组(Tuple):什么时候该用不可变的元组?它们在性能和用途上有什么区别?
  • C++使用Thread实现子线程延时重发