synchronized底层原理分析

synchronized底层原理

并发叫号

static : 并发量大的时候会出现 : 跳号.重号.超过最大值

概念

互斥性 :即同一时间只允许一个线程持有某个对象锁

可见性 : 必须保证锁被释放之前,对共享变量所做的修改,对之后获得锁的对象是课件的

用法

修饰 : 静态方法 普通方法

修饰 : 代码块

monitor[监视器] : 每个对象都有一个monitor对象
在这里插入图片描述

  1. 某一线程占有这个对象的时候, 先看monitor的计数器是不是0 ,如果 是0则还没被进程占有,这个时候线程占有这个对象,并且对这对象的monitor +1 ,如果不为0 ,则表示被其他线程占有, 这个线程等待 . 当线程释放占有权的时候 monitor-1 .
  2. 同一线程可以对同一对象进行多次加锁 +1 [可重入锁]

原理分析

javap 反编译的命令

​ 对代码块加synchronized 锁: monitorenter 和 monitorExit 配合使用 [外链图片转存失败(img-bFSUyPOq-1564806854700)(C:\Users\MIMO\AppData\Roaming\Typora\typora-user-images\1564760009254.png)]

[外链图片转存失败(img-75VGIVnM-1564806854703)(C:\Users\MIMO\AppData\Roaming\Typora\typora-user-images\1564760233592.png)]

对方法进行加锁 [加标记]

[外链图片转存失败(img-J9xUXI5V-1564806854705)(C:\Users\MIMO\AppData\Roaming\Typora\typora-user-images\1564760592326.png)]

1.6JDK 之前 重量锁

Java虚拟机对synchronized 进行了优化

对象头与monitor

一个对象实例包含 : 对象头.实例变量.填充数据

[外链图片转存失败(img-wlY8tEXG-1564806854712)(../../AppData/Roaming/Typora/typora-user-images/1564761052243.png)]

对象头 : 加锁的基础 (32bit )

实例变量 :

填充数据 :

无锁状态: 没有加锁

偏向锁 : 在对象第一次被某一线程占有的时候,将是否偏向锁置1 ,锁标记置 01 ,写入线程号,当其他线程访问的时候,竞争,失败 >>> 轻量级锁

很多次被第一次占有它的线程获取次数多 成功

CAS算法 : compare and swap

竞争不激烈的时候适用,

轻量级锁 : 线程有交替适用,互斥性不是很强,CAS失败,00

重量级锁 (等待时间长) : 强互斥,10 等待时间长

因为用户线程和核心线程(非常耗时)

自旋锁 : 竞争失败的时候,不是马上转换级别,而是执行几次空循环,有可能锁被释放

锁消除 : JIT编译的时候把不必要的锁去掉

### Java `synchronized` 关键字的底层实现原理 `synchronized` 是 Java 中用于实现线程同步的关键字,其核心依赖于 **Monitor** 机制以及 JVM 的支持。以下是关于 `synchronized` 底层实现的具体分析: #### 一、`synchronized` 的作用范围 `synchronized` 主要分为两种使用场景: 1. 方法级:通过修饰实例方法或静态方法来实现同步。 2. 块级:通过指定某个对象作为锁来进行细粒度的同步。 无论哪种方式,其实现都基于 **Monitor** 和 **Java 对象头 (Object Header)**[^1]。 --- #### 二、`Monitor` 机制与 Java 对象头 在 JVM 中,每一个 Java 对象都有一个与其关联的 **Monitor**(也称为监视器)。当多个线程尝试进入被 `synchronized` 保护的代码块时,只有获得该 Monitor 锁的线程才能执行代码,其他线程则会被阻塞等待。 - **Java 对象头结构** Java 对象头通常由两部分组成:Mark Word 和 Class Pointer。其中 Mark Word 存储了对象的状态信息,包括哈希码、GC 标记位、锁状态标志等。当线程试图获取锁时,会修改 Mark Word 来记录当前持有锁的线程 ID[^3]。 - **锁升级机制** JVM 提供了一种优化策略——锁升级机制,主要包括以下几种状态转换: - **无锁状态**:初始状态下没有任何线程竞争。 - **偏向锁**:如果只有一个线程访问共享资源,则可以直接将锁偏向给这个线程,减少开销。 - **轻量级锁**:当有第二个线程尝试获取同一把锁时,JVM 将锁膨胀为轻量级锁,并利用 CAS 操作争夺锁所有权。 - **重量级锁**:如果多次争抢失败,则退化为重量级锁,此时涉及操作系统级别的线程调度和上下文切换。 --- #### 三、字节码层面的表现 从 JDK 编译后的 `.class` 文件来看,`synchronized` 的实现主要体现在两个指令上:`monitorenter` 和 `monitorexit`[^2]。 - 当线程进入 `synchronized` 代码块时,会先执行 `monitorenter` 指令以尝试获取锁; - 如果成功获取锁,则允许继续执行后续逻辑;否则挂起直到锁可用为止。 - 离开代码块时自动调用 `monitorexit` 进行解锁操作。 下面是一个简单的例子及其对应的反汇编结果: ```java public class Test { public synchronized void method() { System.out.println("Synchronized Method"); } } ``` 经过反编译后可以看到如下字节码片段: ```asm 0 aload_0 1 dup 2 astore_1 3 monitorenter // 获取锁 4 getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 7 ldc #3 // String Synchronized Method 9 invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 12 aload_1 13 monitorexit // 释放锁 14 goto 21 17 astore_2 18 aload_1 19 monitorexit // 异常情况下也要确保释放锁 20 athrow 21 return ``` 上述流程清晰展示了如何通过字节码完成加锁与解锁的过程。 --- #### 四、常见的面试问题总结 围绕 `synchronized` 的底层实现,可能会遇到以下几个典型问题:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值