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

Java并发机制的底层实现原理


Java 代码在编译后会变成 Java 字节码 ,字节码被类加载器加载到 JVM 里, JVM 执行字节码,最终转化为汇编指令在 CPU 上执行。

Java 中使用的并发机制依赖于 JVM 的实现和 CPU 的指令。


1. volatile


1.1 作用

在 Java 中, 如果一个字段被 volatile 修饰,那么 Java 内存模型将确保所有线程看到这个变量的值的一致的。保证了 可见性 和 有序性。


1.2 volatile 是如何保证可见性的呢?

有 volatile 变量修饰符的共享变量的 Java 代码, 在转变为汇编语言时候 会对其加上特殊指令(根据硬件不同有差异,但是效果一致)。有这个特殊指令的汇编代码在多核处理器上运行时会发生两件事:

  1. 将当前处理器缓存行的数据写回到系统内存。
  2. 这个写回内存的操作会使其他缓存了该内存地址的 CPU 里的数据无效。

为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内部缓存(LI、L2 或其他 )后再进行操作,但操作完不知道何时会写到内存。如果对声明了volatile 的变量进行写操作,JVM 就会向处理器发送一条有 lock 前缀的指令,将这个变量所在缓存行的数据写回到系统内存。

但是,就算写回到内存,如果其他处理器缓存的值还是旧的,再执行计算操作就会有问题。所以,在多处理器下,为了保证各个处理器的缓存是一至的,就会实现缓存一致性协议。每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改后,它就会将当前处理的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存把数据读到处理器缓存里。

下面具体讲解 volatile 的两条实现原则。

1)lock 前缀指令会引起处理器缓存回写到内存。

lock 前缀指令导致在执行指令期间,声言处理器的 LOCK# 信号。在多处理器环境中,LOCK# 信号确保在声言该信号期间,处理器可以独占任何共享内存。但是,在最近的处理器里,LOCK #信号一般不锁总线,而是锁缓存,毕竟锁总线的开销比较大。对于 Intel486 和 Pentium 处理器,在锁操作时,总是在总线上声言LOCK#信号。但在P6和目前的处理器中,如果访问的内存区域已经缓存在处理器内部,则不会声言LOCK#信号。相反,它会锁定这块内存区域的缓存并回写到内存,同时使用缓存一致性机制来确保修改的原子性,此操作被称为“缓存锁定”。缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据。

2) 一个处理器的缓存回写到内存会导致其他处理器的缓存无效。

IA-32处理器和 Intel64处理器使用 MESI(修改、独占、共享、无效)控制协议去维护内部缓存和其他处理器缓存的一致性。在多核处理器系统中进行操作的时候,IA-32 和Intel 64处理器能嗅探其他处理器访问系统内存和它们的内部缓存。处理器使用嗅探技术保证它的内部缓存、系统内存和甚他处理器的缓存的数据在总线上的一致性。例如,在 Pentium 和 P6 family 处理器中,如果通过嗅探一个处理器来检测其他处理器打算写内存地址,而这个地址当前处于共享状态,那么正在嗅探的处理器将使它的缓存行无效,在下次访问相同内存地址时,强制执行缓存行填充。



2. synchronized


在 Java 中,每一个对象都可以作为锁。synchronized 具体表现形式有以下三种:

  • 修饰普通方法:锁的是当前实例对象。
  • 修饰类方法:锁的锁当前类的 Class 对象。
  • 修饰同步方法:锁的锁 synchronized 括号里配置的对象。

JVM 基于进入和退出 Monitor 对象来实现同步。

3. 原子操作的实现原理

原子操作 意为 “不可中断的一个或一些列操作”。

3.1 术语定义

CPU 术语定义


3.2 处理器如何实现原子操作

最新的处理器能自动保证单个处理器对同一个缓存行里进行的操作是原子的,但是复杂的内存操作处理是不能保证其原子性的。

因此,处理器提供总线锁定和缓存行锁定两个机制来保证复杂内存操作的原子性。

3.2.1 使用总线锁定保证原子性

如果多个处理器同时对共享变量进行读改写操作(i++就是经典的读改与操作),那么共享变量就会被多个处理器同时操作,这样读改写操作就不是原子的,操作完之后共享变量的值会和期望的不一致。

原因可能是多个处理器同时从各自的缓存中读取变量 i, 分别进行加 1 操作,然后分别写人系统内存中。那么,想要保证读改写共享变量的操作是原子的,就必须保证 CPU1 读改写共享变量的时候,CPU2 不能操作缓存该共享变量内存地址的缓存。

处理器使用总线锁定来解决这个问题。所谓总线锁定就是使用处理器提供的一个 LOCK# 信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,该处理器可以独占共享内存。

3.2.2 使用缓存行锁定保证原子性

在同一时刻,我们保证对某个内存地址的操作是原子性即可,但总线锁定把 CPU 和内存之间的通信锁住了,这使得锁定期间,其他处理器不能操作其他内存地址的数据,所以总线锁定的开销比较大,目前处理器在某些场合下使用缓存锁定代替总线锁定来进行优化。

频繁使用的内存会缓存在处理器的 L1 ,L2 和 L3 高速缓存里,那么原子操作就可以直接在处理器内部缓存中进行,并不需要声明总线锁定,在目前的处理器中可以使用 “缓存锁定” 的方式来实现复杂的原子性。

所谓"缓存锁定"是指内存区域如果被缓存在处理器的缓存行中,并且在 Lock 操作期间被锁定,那么当它执行锁操作回写到内存时,处理器不在总线上声言 LOCK# 信号,而是修改内部的内存地址,并允许它的缓存一致性机制来保证操作的原子性。缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据。当其他处理器回写已被锁定的缓存行的数据时,会使缓存行无效。

两种情况下,处理器不会使用缓存行锁定:1️⃣ 当操作的数据没有缓存在同一缓存行时;2️⃣ 有些处理器不支持缓存行;


3.2.3 Java 如何实现原子操作

在 Java 中可以通过 循环 CAS 和 锁 的方式来实现原子操作。




文章转载自:

http://1S4Prfkj.wmgLg.cn
http://UXjnSkVo.wmgLg.cn
http://45SceXqU.wmgLg.cn
http://RauacAgQ.wmgLg.cn
http://MWvFSpd7.wmgLg.cn
http://KzkyUZC4.wmgLg.cn
http://0yMgGLHl.wmgLg.cn
http://ejEaIe1x.wmgLg.cn
http://KFRuuPS8.wmgLg.cn
http://UftzWnwW.wmgLg.cn
http://NeD4G6QP.wmgLg.cn
http://7q7oet3g.wmgLg.cn
http://gHUKu94X.wmgLg.cn
http://QpQy2yOe.wmgLg.cn
http://m2nf97v7.wmgLg.cn
http://MIEXxp8r.wmgLg.cn
http://RWnC9MoT.wmgLg.cn
http://557AzyZ6.wmgLg.cn
http://VDsy9ipA.wmgLg.cn
http://hmRcvNfc.wmgLg.cn
http://uA7Wfe7W.wmgLg.cn
http://n7luQGQI.wmgLg.cn
http://0Itmr5JC.wmgLg.cn
http://W4am3LEn.wmgLg.cn
http://iiNMLqhr.wmgLg.cn
http://H06gKxDo.wmgLg.cn
http://7iPIN5zp.wmgLg.cn
http://YqHwsadu.wmgLg.cn
http://JFZVMS3M.wmgLg.cn
http://VmdbwnRg.wmgLg.cn
http://www.dtcms.com/a/369921.html

相关文章:

  • 数据结构:查找
  • PyQt5 多线程编程与排错技术文档
  • Linux 使用pip报错(error: externally-managed-environment )解决方案
  • Flask论坛与个人中心页面开发教程完整详细版
  • 【PostgreSQL】如何实现主从复制?
  • 进程与服务管理:systemd / sysvinit 服务管理、定时服务(cron / at)
  • Java全栈工程师面试实录:从基础到高并发场景的技术探索
  • 2025高教社国赛数学建模A题参考论文35页(含代码和模型)
  • 前缀和、子矩阵的和;差分、差分矩阵
  • 如何在 FastAPI 中巧妙覆盖依赖注入并拦截第三方服务调用?
  • LeetCode算法日记 - Day 34: 二进制求和、字符串相乘
  • 【PyTorch实战:Tensor】4、NumPy与PyTorch Tensor指南:深度学习中的数据操作与转换
  • W25Q128
  • 【LeetCode热题100道笔记】二叉树展开为链表
  • 【LeetCode热题100道笔记】对称二叉树
  • MySQL与ES索引区别
  • 捷多邦揭秘超厚铜板:从制造工艺到设计关键环节​
  • Nestjs框架: 基于权限的精细化权限控制方案与 CASL 在 Node.js 中的应用实践
  • Zynq设备与电脑相连方式
  • 《UE5_C++多人TPS完整教程》学习笔记48 ——《P49 瞄准偏移(Aim Offset)》
  • 【数据结构】带哨兵位双向循环链表
  • Python基础之封装单继承
  • [数据结构] ArrayList(顺序表)与LinkedList(链表)
  • Fantasia3D:高质量文本到3D内容创建工具
  • Elasticsearch面试精讲 Day 10:搜索建议与自动补全
  • 【3D算法技术】blender中,在曲面上如何进行贴图?
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘mkdocs’问题
  • 【牛客刷题-剑指Offer】BM18 二维数组中的查找:一题四解,从暴力到最优
  • 推荐的Java服务环境:JDK17+ZGC(JDK 21的ZGC支持分代回收,性能更高)
  • [光学原理与应用-431]:非线性光学 - 能生成或改变激光波长的物质或元件有哪些?