synchronized关键字原理

本文详细解析了synchronized关键字的三种使用方式及其实现原理,包括同步普通方法、静态方法和同步块,阐述了JVM如何通过对象监视器实现线程同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不管是在校招还是社招中的面试,常会被问到volatile与synchronized的区别,在volatile关键字剖析文章中已经介绍了相关的原理,在本篇中将剖析synchronized关键字原理

众所周知 synchronized 关键字是解决并发问题常用解决方案,有以下三种使用方式:

  • 同步普通方法,锁的是当前对象
  • 同步静态方法,锁的是当前 Class 对象
  • 同步块,锁的是 () 中的对象

实现原理:

  • JVM 是通过进入、退出对象监视器( Monitor )来实现对方法、同步块的同步的
  • 具体实现是在编译之后在同步方法调用前加入一个 monitor.enter 指令
    在退出方法和异常处插入 monitor.exit 的指令
  • 其本质就是对一个对象监视器( Monitor )进行获取,而这个获取过程具有排他性从而达到了同一时刻只能一个线程访问的目的
  • 而对于没有获取到锁的线程将会阻塞到方法入口处,直到获取锁的线程 monitor.exit 之后才能尝试继续获取锁

流程如下图所示:
在这里插入图片描述

### Java 中 `synchronized` 关键字的底层实现原理 #### 同步代码块的结构 当定义一个同步方法或同步代码块时,实际上是在告诉 JVM 需要对该段代码进行锁定处理。对于给定的例子: ```java private int i = 0; public void fun(){ synchronized(this){ i++; } } ``` 这段代码表示只有获得当前实例 (`this`) 的锁之后才能进入并执行 `{}` 大括号内的语句[^1]。 #### 底层编译后的指令变化 在 JVM 层面,每当遇到 `synchronized` 修饰的方法调用或是显式的 `synchronized` 块时,会转换成特定的操作码来控制锁的行为。具体来说就是通过 `monitorenter` 和 `monitorexit` 操作符来进行加锁和解锁操作。每次进入由 `synchronized` 定义的临界区之前都会先执行一次 `monitorenter` 来尝试获取对象上的监视器(即锁),而一旦退出该区域则自动触发相应的 `monitorexit` 以释放持有的锁资源[^3]。 #### 锁的状态变迁与优化策略 JVM 对于锁有着多种不同的状态管理方式,包括但不限于无锁、偏向锁、轻量级锁以及重量级锁等形式。这些状态之间的转变取决于实际运行环境中的竞争程度等因素。例如,在没有任何其他线程试图访问相同对象的情况下,默认采用的是偏向锁模式;而在多线程并发争抢同一把锁的情形下,则可能升级至更重级别的锁形式如膨胀为重量级锁[^5]。 - **无锁**:最初始状态下,对象头中仅保存一些基本信息而不涉及任何锁机制。 - **偏向锁**:允许单一线程长时间持有某个对象的独占使用权,减少不必要的上下文切换开销。 - **轻量级锁**:适用于短时间内的低冲突场景,利用原子性的 CAS (Compare And Swap) 操作快速完成上锁过程。 - **重量级锁**:当上述几种简化版无法满足需求时才会启用的传统 Monitor 实现方案,通常伴随着较高的性能损耗。 综上所述,`synchronized` 是一种基于 JVM 内部监控器机制构建而成的关键字,它能够有效地保障共享数据的一致性和可见性,尽管相比某些高级别的并发工具类而言可能会带来一定的性能损失,但在大多数情况下仍然是简单易用的选择之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值