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

深入了解synchronized

1、synchronized 底层实现原理

        synchronized 是 Java 的关键字,但它的功能并不是由 Java 代码直接实现的,而是由 ​JVM 底层(主要是对象监视器机制)​​ 提供支持;核心概念包括:   

        1、​Monitor(监视器 / 管程)​

                在 Java 中,​每个对象都有一个与之关联的 Monitor(监视器锁)​,它用于控制多个线程对临界资源的访问,是实现 synchronized 的基础。

  • 每个 Java 对象都可以作为一个 ​锁(Lock)​,即 ​Monitor 对象
  • 当线程进入 synchronized 方法/代码块时,它必须先 ​获取该对象的 Monitor 锁
  • 如果锁被其他线程占用,则当前线程进入 ​阻塞状态(BLOCKED)​,等待锁释放;
  • 当线程退出 synchronized 块/方法时,会 ​自动释放 Monitor 锁

        2、​对象头与 Mark Word(与锁状态相关)​

                在 JVM 中,每个对象在内存中的布局分为三部分:

                        1、对象头(Object Header)​

                        2、​实例数据(Instance Data)​

                        3、​对齐填充(Padding)​

其中,​对象头包含 Mark Word(标记字段)​,它存储了对象的 ​哈希码、GC 分代年龄、锁状态标志等信息。

🎯 ​锁的信息是记录在对象头的 Mark Word 中的!这是 synchronized 实现锁机制的关键。​

        3、​Monitor 的底层实现(C++层面,HotSpot 虚拟机)​

                在 HotSpot 虚拟机中,每个 Java 对象都与一个 ​Monitor 对象关联,这个 Monitor 是用 ​C++ 实现的,核心结构是 ObjectMonitor,它包含如下关键信息:

  • _owner:指向持有该 Monitor 锁的线程
  • _EntryList:等待获取锁的线程队列(阻塞态)
  • _WaitSet:调用了 wait() 方法的线程集合

当线程进入 synchronized 块时:

  1. 尝试通过 CAS(Compare And Swap)获取对象的 Monitor;
  2. 如果获取失败,线程进入阻塞状态,进入 _EntryList
  3. 当锁被释放时,JVM 会唤醒 _EntryList 中的某个线程来竞争锁。

2、synchronized 的锁升级机制(锁优化)

        在 Java 6 以后,JVM 对 synchronized 进行了大量的性能优化,引入了 ​锁升级(Lock Escalation)机制,即:​根据竞争情况,锁的状态会从轻量级逐步升级到重量级,以提升性能。​

🔒 锁的四种状态(由低到高,优化路径):

锁状态说明适用场景实现方式
​无锁状态​对象刚创建,还没有线程竞争初始状态-
​偏向锁(Biased Lock)​​假设锁通常由同一个线程获得,避免频繁的同步操作单线程访问同步块对象头记录偏向线程ID,无需 CAS
​轻量级锁(Lightweight Lock)​​当有少量线程交替访问,没有真正竞争,采用 CAS 自旋方式获取锁多线程交替但低竞争基于 CAS 和栈帧中的 Lock Record
​重量级锁(Heavyweight Lock)​​多个线程真正竞争同一个锁,线程会进入阻塞状态,由操作系统介入管理高并发、激烈竞争基于 Monitor,线程进入 WAITING 状态

 锁升级简化流程:

        1、无锁 → 偏向锁​:如果检测到总是同一个线程获取锁,JVM 会启用偏向锁,避免同步开销。

        2、偏向锁 → 轻量级锁​:当有第二个线程尝试获取锁时,偏向锁会撤销,升级为轻量级锁。

        3、​轻量级锁 → 重量级锁​:如果自旋等待超过阈值(或竞争激烈),轻量级锁会升级为重量级锁,线程进入阻塞。

✅ ​目的:避免所有同步都直接使用重量级锁(性能差),通过锁升级,在无竞争或低竞争时使用更轻量的机制。​

3、synchronized 与 ReentrantLock 对比

对比维度​synchronized​​ReentrantLock​
​锁类型​JVM 内置关键字,隐式锁JDK 提供的类,显式锁(需要手动加锁/释放)
​使用方式​直接加在方法或代码块上需要使用 lock() 和 unlock() 方法
​锁获取与释放​自动管理(进入/退出时)必须手动调用 lock() 和 unlock(),通常配合 try-finally
​可中断性​❌ 不支持中断等待锁✅ 支持 lockInterruptibly()
​超时机制​❌ 不支持尝试获取锁超时✅ 支持 tryLock(long timeout, TimeUnit unit)
​公平性​❌ 默认非公平锁✅ 支持公平锁和非公平锁(构造方法指定)
​条件变量​只能配合 wait() / notify()✅ 支持多个 Condition,更灵活的线程协作
​性能(Java 6+)​​优化良好,大多数场景足够高竞争下可能表现更好,但使用复杂

总结:​

  • 如果使用场景 ​不复杂,追求代码简洁,使用 synchronized 就足够了
  • 如果需要 ​更灵活的锁控制(如超时、可中断、公平性、多个条件变量),选择 ReentrantLock。

4、synchronized 与 volatile 对比

对比维度​synchronized​​volatile​
​作用​保证原子性、可见性、有序性(互斥访问)仅保证 ​可见性和有序性,不保证原子性
​线程安全​能保证复合操作的线程安全(如 i++)不能保证复合操作(如 i++ 是读改写三步操作)
​阻塞机制​获取不到锁的线程会 ​阻塞​不涉及阻塞,线程始终在运行
​使用场景​用于方法或代码块,控制多线程对共享资源的访问用于修饰变量,保证变量的可见性
​性能​相对较重(尤其在竞争激烈时)更轻量,适合一写多读的场景
​底层实现​基于 Monitor 锁基于内存屏障(Memory Barrier)

总结:​

  • volatile 适用于 ​一个线程写、多个线程读的变量同步
  • 但 ​不能保证复合操作(如 i++、check-then-act)的原子性,不能替代 synchronized。​

5、synchronized、ReentrantLock、volatile总结

机制作用是否阻塞是否可重入是否公平适用场景
​synchronized​方法/代码块同步,保证原子性、可见性、有序性是(自动)✅ 是❌ 非公平(默认)简单线程同步,代码简洁优先
​ReentrantLock​显式锁,更灵活的线程同步控制是(手动)✅ 是✅ 可配置公平/非公平需要高级功能:超时、中断、多条件
​volatile​保证变量的可见性与有序性,不保证原子性不适用不适用单写多读、状态标志等轻量同步
http://www.xdnf.cn/news/20326.html

相关文章:

  • 2025世界职校技能大赛总决赛争夺赛汽车制造与维修赛道比赛资讯
  • 告别Qt Slider!用纯C++打造更轻量的TpSlider组件
  • 一文了解太阳光模拟器的汽车材料老化测试及标准解析
  • 企业级 AI Agent 开发指南:基于函数计算 FC Sandbox 方案实现类 Chat Coding AI Agent
  • 集成学习 | MATLAB基于CNN-LSTM-Adaboost多输入单输出回归预测
  • 调试技巧:Chrome DevTools 与 Node.js Inspector
  • 从零开始学大模型之大模型训练流程实践
  • Multisim14.0(五)仿真设计
  • OpenResty 和 Nginx 到底有啥区别?你真的了解吗!
  • 分布式3PC理论
  • Qt---字节数据处理QByteArray
  • 【FastDDS】Layer Transport ( 02-Transport API )
  • k8s基础练习环境搭建
  • 服务器硬盘“Unconfigured Bad“状态解决方案
  • WebSocket:实现实时通信的革命性技术
  • Iwip驱动8211FS项目——MPSOC实战1
  • 当服务器出现网卡故障时如何检测网卡硬件故障并解决?
  • Grizzly_高性能 Java 网络应用框架深度解析
  • 基于智能合约实现非托管支付
  • Qt添加图标资源
  • conda配置pytorch虚拟环境
  • git cherry-pick 用法
  • dpdk example
  • 自动化流水线
  • Ubuntu 22 redis集群搭建
  • 电脑越用越卡?C盘红到预警?这款清理神器帮你一键 “减负”!
  • 跨域请求问题浅解
  • 深入浅出 QComboBox:Qt 中的下拉列表组件
  • uniapp开发前端静态视频界面+如何将本地视频转换成网络地址
  • 2024年9月GESPC++三级真题解析(含视频)