synchronized 锁升级

简介: JDK 6 引入的 synchronized 锁升级机制,通过偏向锁、轻量级锁和重量级锁的动态切换,优化了多线程同步性能。该机制根据竞争情况逐步升级锁状态,减少线程阻塞和系统调用开销,从而提升并发效率。

synchronized 锁升级是 JDK 6 引入的重要优化,通过偏向锁、轻量级锁、重量级锁的逐步升级策略,减少了传统重量级锁的性能开销。以下是锁升级的详细过程和原理:

1. 锁升级的核心动机

  • 传统重量级锁的问题:依赖操作系统的互斥量(Mutex)实现,线程阻塞和唤醒需从用户态切换到内核态,性能损耗大。
  • 优化思路:根据实际场景动态调整锁的粒度,避免不必要的重量级锁开销。

2. 锁状态与对象头

每个 Java 对象的对象头(Mark Word)中存储着锁状态信息,不同状态下 Mark Word 的结构如下:

锁状态 存储内容 标志位
无锁 对象哈希码、分代年龄 01
偏向锁 线程 ID、Epoch、分代年龄 01
轻量级锁 指向线程栈中锁记录的指针 00
重量级锁 指向 Monitor 的指针 10
GC 标记 11

3. 锁升级的具体过程

(1)偏向锁(Biased Locking)

  • 适用场景:只有一个线程访问同步块,无竞争。
  • 获取过程
    1. 当第一个线程 T1 访问同步块时,JVM 通过 CAS 操作将线程 ID 写入 Mark Word,同时将标志位设为 01(偏向锁)。
    2. 后续 T1 再次进入同步块时,无需任何同步操作,直接判断 Mark Word 中的线程 ID 是否为自己,若是则直接执行。
  • 撤销过程
    1. 当有其他线程 T2 尝试竞争该锁时,T1 会被暂停,JVM 检查 T1 是否仍在执行同步块:
      • 若已退出:Mark Word 恢复为无锁状态,T2 可竞争并获取偏向锁。
      • 若仍在执行:偏向锁升级为轻量级锁,T1 继续执行,T2 自旋等待。
  • 批量重偏向与撤销
    • 当一个类的对象频繁发生偏向锁撤销时,JVM 会认为该类不适合偏向锁,批量将该类的对象偏向锁撤销或禁用。

(2)轻量级锁(Lightweight Lock)

  • 适用场景:多个线程交替访问同步块,无实际竞争。
  • 加锁过程
    1. 线程进入同步块前,在当前线程的栈帧中创建锁记录(Lock Record),并将 Mark Word 复制到锁记录中(Displaced Mark Word)。
    2. 通过 CAS 尝试将 Mark Word 更新为指向锁记录的指针:
      • 成功:获取轻量级锁,Mark Word 标志位变为 00
      • 失败:表示有其他线程竞争,锁升级为重量级锁。
  • 解锁过程
    1. 通过 CAS 将锁记录中的 Displaced Mark Word 替换回 Mark Word。
    2. 若替换成功:锁释放完成。
    3. 若替换失败:表示有其他线程在竞争,已升级为重量级锁,需唤醒被阻塞的线程。

(3)重量级锁(Heavyweight Lock)

  • 适用场景:多个线程同时竞争锁。
  • 升级过程
    1. 当轻量级锁竞争失败时,锁升级为重量级锁,Mark Word 存储指向 Monitor 的指针,标志位变为 10
    2. 未获取到锁的线程会被阻塞(进入 Monitor 的 EntryList),释放 CPU 资源。
  • 释放过程
    1. 持有锁的线程执行完同步块后,释放 Monitor。
    2. 唤醒 EntryList 中的线程重新竞争。

4. 锁升级的流程图

无锁状态 → 偏向锁(单线程) → 轻量级锁(多线程交替) → 重量级锁(多线程竞争)

5. 锁升级的关键点

  • 不可逆性:锁只能升级,不能降级(但偏向锁可撤销为无锁)。
  • 自旋锁(Spin Lock):轻量级锁竞争时,线程会短暂自旋等待锁释放,避免直接阻塞(JDK 6 后自旋次数可自适应)。
  • 锁粗化(Lock Coarsening):JVM 会将多个连续的加锁、解锁操作合并为一个,减少锁的获取和释放次数。
  • 锁消除(Lock Elimination):对不可能存在共享资源竞争的锁进行消除(如局部变量锁)。

6. 性能对比

锁类型 优点 缺点 适用场景
偏向锁 无同步开销,单线程性能极佳 存在锁撤销开销 单线程访问同步块
轻量级锁 竞争不激烈时避免线程阻塞 自旋消耗 CPU 多线程交替访问
重量级锁 保证线程安全,处理高竞争场景 线程阻塞和唤醒开销大 多线程同时竞争

7. 优化建议

  • 减少锁竞争:通过减小锁粒度、缩短锁持有时间降低竞争。
  • 批量偏向锁:对于频繁创建的对象,可通过 JVM 参数 -XX:+UseBiasedLocking 启用偏向锁。
  • 高并发场景:考虑使用 ReentrantLockConcurrentHashMap 等更灵活的同步工具。

总结

锁升级机制通过动态调整锁的状态,在不同场景下平衡了性能和线程安全:

  • 偏向锁:优化单线程场景,几乎无同步开销。
  • 轻量级锁:处理多线程交替访问,避免内核态切换。
  • 重量级锁:应对高竞争场景,保证线程安全。

理解锁升级原理有助于写出更高效的多线程代码,避免不必要的性能损耗。

目录
相关文章
|
5月前
|
安全
一文搞懂synchronized锁的升级过程
synchronized锁的升级过程包括偏向锁、轻量锁和重量级锁。偏向锁在无竞争时可重复使用,轻量锁通过CAS自旋实现多线程竞争,重量级锁则会导致线程阻塞,涉及用户态到内核态的切换。CAS(比较并交换)用于实现乐观锁,保证原子性操作,但可能引发CPU资源浪费。文中还展示了手写锁的升级实现代码。
291 0
|
存储 缓存 监控
美团面试:说说OOM三大场景和解决方案? (绝对史上最全)
小伙伴们,有没有遇到过程序突然崩溃,然后抛出一个OutOfMemoryError的异常?这就是我们俗称的OOM,也就是内存溢出 本文来带大家学习Java OOM的三大经典场景以及解决方案,保证让你有所收获!
6524 1
美团面试:说说OOM三大场景和解决方案? (绝对史上最全)
|
Java
G1垃圾回收器的工作流程
G1垃圾回收器的工作流程
2326 0
|
缓存 Java 应用服务中间件
Tomcat是如何打破"双亲委派"机制的?
上文我们详细了解了类加载以及什么是双亲委派机制,相信很多童鞋都了解Tomcat打破了双亲委派机制,本文将对Tomcat为什么要打破双亲委派机制,以及Tomcat是如何打破双亲委派机制的,进行完整性的复盘与解析。
3914 0
Tomcat是如何打破"双亲委派"机制的?
|
8月前
|
存储 缓存 Java
我们来详细讲一讲 Java NIO 底层原理
我是小假 期待与你的下一次相遇 ~
269 2
|
7月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 > Java系统属性 > application.properties > application.yml > application.yaml。
1133 0
|
7月前
|
缓存 Java API
Java 面试实操指南与最新技术结合的实战攻略
本指南涵盖Java 17+新特性、Spring Boot 3微服务、响应式编程、容器化部署与数据缓存实操,结合代码案例解析高频面试技术点,助你掌握最新Java技术栈,提升实战能力,轻松应对Java中高级岗位面试。
547 0
|
Java 存储
线程池的核心参数有哪些?
线程池七大核心参数:核心/最大线程数、线程保持时间及单位、阻塞队列、线程工厂与拒绝策略。
1013 79
|
11月前
|
存储 缓存 人工智能
【原理】【Java并发】【synchronized】适合中学者体质的synchronized原理
本文深入解析了Java中`synchronized`关键字的底层原理,从代码块与方法修饰的区别到锁升级机制,内容详尽。通过`monitorenter`和`monitorexit`指令,阐述了`synchronized`实现原子性、有序性和可见性的原理。同时,详细分析了锁升级流程:无锁 → 偏向锁 → 轻量级锁 → 重量级锁,结合对象头`MarkWord`的变化,揭示JVM优化锁性能的策略。此外,还探讨了Monitor的内部结构及线程竞争锁的过程,并介绍了锁消除与锁粗化等优化手段。最后,结合实际案例,帮助读者全面理解`synchronized`在并发编程中的作用与细节。
806 8
【原理】【Java并发】【synchronized】适合中学者体质的synchronized原理
|
11月前
|
NoSQL Java Redis
springboot怎么使用Redisson
通过以上步骤,已经详细介绍了如何在Spring Boot项目中使用Redisson,包括添加依赖、配置Redisson、创建配置类以及使用Redisson实现分布式锁和分布式集合。Redisson提供了丰富的分布式数据结构和工具,可以帮助开发者更高效地实现分布式系统。通过合理使用这些工具,可以显著提高系统的性能和可靠性。
3718 34