synchronized的实现原理
Synchronized的特性
synchronized 是java中的关键字,主要用于加锁,来实现同步,具体实现形式有以下三种:
1.对普通方法加锁,锁是当前实例对象
2.对静态方法加锁,锁是当前类的Class实例,因为Class数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;
3.对对象实例加锁,锁是Synchronized括号里对象实例。
synchronized 内置锁 是一种 对象锁(锁的是对象而非引用变量),作用粒度是对象 可以用来实现对临界资源的同步互斥访问 ,是可重入的。其可重入最大的作用是避免死锁,如:子类同步方法调用了父类的同步方法,如果没有可重入的特性,就会发生死锁。
Synchronized的同步实现
Synchronized的锁的实现是基于JVM进入和退出monitor对象来实现的。
monitor对象有2个关键指令monitorenter和monitorexit,具体就是在编译过程中把monitorenter指令插入到同步代码块开始位置,把monitorexit指令插入退出或异常的位置。
线程执行同步代码块的时首先需要获取锁,即尝试获取monitor对象的所有权,具体过程如下:
首先线程执行指令monitorenter指令尝试获取monitor的所有权,如果monitor的进入数为0,则线程进入进入monitor,并且把进入修改为1,当前线程就持有了锁;如果线程进入monitor时,发现进入数大于0,则会判断monitor的持有者是否为当前线程,如果是当前线程则表示只是重新进入,则对monitor的进入数+1;如果monitor的所有权不是被当前线程持有,线程进入阻塞状态,直到monitor的进入数等于0,再次重新获取monitor的所有权。
对象头
java中每个对象都包含三部分:对象头、实例数据、对齐填充(非必须)。synchronized使用的锁是存在对象的对象头中,对象头主要包含了2部分数据,Mark Word(存储对象的hashCode、分代年龄和锁标记位)、Class Metadata Address(存储对象类型数据的指针)。
锁的升级和对比
synchronized在JDK 1.6以后引入锁的状态级别,从低到高为:无锁、偏向锁、轻量级锁、重量级锁;
锁可以根据竞争进行粗话升级,但是不能降级。
偏向锁
当一个线程访问同步代码块获取锁时,会在对象头和栈帧中的锁记录中存储锁偏向的线程id,以后该线程再次进入和退出同步代码块时不需要信息CAS操作来加锁或解锁。
首先执行monitorenter命令尝试获取锁,查询Mark Word中存储的线程id是否为当前线程id,如果为当前线程id,则直接执行同步代码,如果不是当前线程id,则判断是否开启了偏向锁;
当偏向锁标识为1是,使用CAS竞争锁,竞争成功,尝试把Mark Word中的偏向锁指向自己;竞争失败,表示当前有多个线程在竞争锁,当到达全局安全点时,获得偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后被阻塞在安全点的线程继续往下执行同步代码块;
偏向锁的机制:竞争时才会释放锁,线程是不会主动去释放偏向锁,需要等待其他线程来竞争。偏向锁的撤销需要 等待全局安全点(这个时间点是上没有正在执行的代码)
轻量锁
轻量锁加锁
线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为DisplacedMark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
轻量锁解锁
轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。
因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时,都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮的夺锁之争。
__EOF__

本文链接:https://www.cnblogs.com/wangzun/p/13454495.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构