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

Java 的 synchronized

synchronized 是 java 内置的关键字,用于多线程的同步操作。

synchronized 修饰在方法或代码块上时,会对特定的对象或类加锁,从而确保同一时刻只有一个线程能执行加锁的代码块。

  • synchronized 修饰方法:会在方法的访问标志中增加一个 ACC_SYNCHRONIZED 标志。每当一个线程访问该方法时,JVM 会检查方法的访问标志。如果包含 ACC_SYNCHRONIZED 标志,线程必须先获得该方法对应的对象的监视器锁(即对象锁),然后才能执行该方法,从而保证方法的同步性。
  • synchronized 修饰代码块:会在代码块的前后插入 monitorentermonitorexit 字节码指令。可以把 monitorenter 理解为加锁,monitorexit理解为解锁。

synchronized 无法完全禁止指令重排序,但能通过内存屏障保证多线程环境下的有序性。对于需要严格禁止重排序的场景,应优先选择 volatile。


实现原理

通过 JVM 的 Monitor(监视器锁) 和 对象头(Object Header)。

对象头(Object Header)
  • mark word:记录对象的哈希码、分代年龄、锁标志位等。
  • klass pointer:指向对象类型的元信息

64 位时 MarkWord 在不同状态下的内存布局

在这里插入图片描述
Mark Word 是实现 synchronized 的关键,因为它会根据锁的状态保存不同的信息,具体包括:

  • 未锁定状态:Mark Word 存储对象的哈希码和 GC 分代信息。
  • 偏向锁状态:Mark Word 保存获取该锁的线程 ID 和一些偏向锁标志位。
  • 轻量级锁状态:Mark Word 存储的是指向栈中锁记录的指针。
  • 重量级锁状态:Mark Word 存储的是指向 Monitor 对象的指针。
对象结构图

锁升级过程

synchronized 的锁升级过:无锁–>偏向锁–>轻量级锁–>重量级锁。

偏性锁
  • 加锁过程:当有一个线程去获取锁时,jvm 会将该线程的 id 记录在对象头 mark word 中,等线程再次获锁时,jvm 无须在进行加锁操作。
  • 撤销偏向锁:如果在偏向锁持有期间,另一个线程请求同一把锁,jvm 会撤销偏向锁并升级为轻量级锁。
轻量级锁
  • 加锁过程:当线程获取锁时,jvm 会在当前线程的栈帧中创建一个锁记录,并将对象头中的 mark word 复制到锁记录中,然后利用 CAS 将对象头的 mark word 替换为指向锁记录的指针, 如果成功,则该线程获得轻量级锁,如果失败,表示其他线程已经持有该锁,此时会升级为重量级锁。
  • 解锁过程:线程退出同步块时,JVM 会将对象头中的 Mark Word 恢复为原始值。

轻量级锁 CAS 失败了之后,不会有自旋操作,会直接进入重量级锁膨胀过程。在已经升级成重量级锁之后,线程如果没有争抢到锁,会进行一段自旋等待锁的释放。

重量级锁

当锁竞争激烈时,JVM 会升级为重量级锁,重量级锁使用操作系统的互斥量(Mutex) 机制来实现线程的阻塞与唤醒。

  • 加锁过程:如果线程无法通过轻量级锁获取锁时,则会升级为重量级锁。
  • 解锁过程:当线程释放重量级锁时,jvm 会唤醒所有阻塞的线程,允许他们再次获取锁。

当重量级锁释放了之后,锁对象是无锁的。有新的线程来竞争的话又会从无锁再到轻量级锁开始后续的升级流程。

锁升级过程总结

偏性锁:当线程第一次获取锁时,jvm 会将当前线程的 id 记录在对象头中,后续该线程再次获取锁时,几乎没有开销。

轻量级锁:当一个线程去获取已经被偏性的锁时,此时锁会升级为轻量级锁。

重量级锁:如果 CAS 失败无法获取锁时,此时锁会升级为重量级锁,线程会被挂起,直到锁被释放。

Synchronized 的可重入性

synchronized 是可重入的,每获取一次锁,计数器加一,释放锁时,计数器减一,直到计数器为 0,锁才会真正释放。

锁消除和锁粗化

  • 锁消除:JVM 会通过逃逸分析判断对象是否只在当前线程使用,如果是,那么会消除不必要的加锁操作。
  • 锁粗化:当多个锁操作频繁出现时,JVM 会将这些锁操作合并,减少锁获取和释放的开销。

修饰静态方法和修饰普通方法的区别

  • 修饰静态方法:锁的是这个类的 Class 对象。也就是说,无论创建了多少个该类的实例,所有的实例共享同一个锁,因为这个锁属于类本身而不是某个对象实例。
  • 修饰实例方法:锁的是当前实例(调用该方法的对象),也就是这个对象的内在锁。这也就是说每个对象实例都有自己独立的锁。

相关文章:

  • 在 Ubuntu linux系统中设置时区的方案
  • React从基础入门到高级实战:React 核心技术 - React Router:路由管理
  • 【操作系统】-4.3.1文件的层次结构
  • 计算机网络技术(二)
  • DAY33 简单神经网络
  • Leetcode 1651. Hopper 公司查询 III
  • 【NIPS 2024】Towards Robust Multimodal Sentiment Analysis with Incomplete Data
  • quill 富文本多张图片排序
  • 大语言模型的完整训练周期从0到1的体系化拆解
  • CS学习网站-geeksforgeeks介绍
  • 历年安徽大学保研上机真题
  • 原生php单元测试
  • Kafka 的日志清理策略:delete 和 compact
  • 决策引擎与规则引擎在交易所业务风控中的建设思路、架构设
  • 历年北京理工大学保研上机真题
  • 使用 Hyperlane 实现 WebSocket广播
  • MIT 6.S081 2020Lab5 lazy page allocation 个人全流程
  • 《技术择时,价值择股》速读笔记
  • [论文品鉴] DeepSeek V3 最新论文 之 MTP
  • 历年北京邮电大学保研上机真题
  • 南京谁做免费网站/推广普通话宣传语100字
  • .net网站制作/南宁seo手段
  • 上海企业网站建设哪家好/八爪鱼磁力搜索引擎
  • 高端网站建设公司哪家公司好/室内设计培训
  • 温州小学网站建设/爱站网ip反域名查询
  • 怎么做福彩网站/最新国内新闻10条