聊聊高并发(三十五)Java内存模型那些事(三)理解内存屏障

聊聊高并发(五)理解缓存一致性协议以及对并发编程的影响 Java作为一个跨平台的语言,它的实现要面对不同的底层硬件系统,设计一个中间层模型来屏蔽底层的硬件差异,给上层的开发者一个一致的使用接口。Java内存模型就是这样一个中间层的模型,它为程序员屏蔽了底层的硬件实现细节,支持大部分的主流硬件平台。要理解Java内存模型以及一些处理高并发的技术手段,理解一些基本的硬件知识是必须的。这篇会说一下跟并发编程相关的一些硬件知识。 一个基本的CPU执行 阅读详情

在聊聊高并发(三十三)从一致性(Consistency)的角度理解Java内存模型 我们说了硬件层提供了满足某些一致性需求的能力,Java内存模型利用了硬件层提供的能力指定了一系列的语法和规则,让Java开发者可以隔绝这种底层的实现专注于并发逻辑的开发。这篇我们来看看硬件层是如何提供这些实现一致性需求的能力的。


硬件层提供了一系列的内存屏障 memory barrier / memory fence(Intel的提法)来提供一致性的能力。拿X86平台来说,有几种主要的内存屏障

1. lfence,是一种Load Barrier 读屏障

2. sfence, 是一种Store Barrier 写屏障

3. mfence, 是一种全能型的屏障,具备ifence和sfence的能力

4. Lock前缀,Lock不是一种内存屏障,但是它能完成类似内存屏障的功能。Lock会对CPU总线和高速缓存加锁,可以理解为CPU指令级的一种锁。它后面可以跟ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG等指令。


内存屏障有两个能力:

1. 阻止屏障两边的指令重排序

2. 强制把写缓冲区/高速缓存中的脏数据等写回主内存,让缓存中相应的数据失效


对Load Barrier来说,在读指令前插入读屏障,可以让高速缓存中的数据失效,重新从主内存加载数据

对Store Barrier来说,在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存


Lock前缀实现了类似的能力,

1. 它先对总线/缓存加锁,然后执行后面的指令,最后释放锁后会把高速缓存中的脏数据全部刷新回主内存。

2. 在Lock锁住总线的时候,其他CPU的读写请求都会被阻塞,直到锁释放。Lock后的写操作会让其他CPU相关的cache line失效,从而从新从内存加载最新的数据。这个是通过缓存一致性协议做的。


再引用一下这篇文章中关于Lock前缀的更多的一些描述 多处理器多线程使用_asm lock指令能保证互斥吗?

“从 P6 处理器开始,如果指令访问的内存区域已经存在于处理器的内部缓存中,则“lock” 前缀并不将引线 LOCK 的电位拉低,而是锁住本处理器的内部缓存,然后依靠缓存一致性协议保证操作的原子性。

IA32 CPU调用有lock前缀的指令,或者如xchg这样的指令,会导致其它的CPU也触发一定的动作来同步自己的Cache。
CPU的#lock引脚链接到北桥芯片(North Bridge)的#lock引脚,当带lock前缀的执行执行时,北桥芯片会拉起#lock
电平,从而锁住总线,直到该指令执行完毕再放开。 而总线加锁会自动invalidate所有CPU对 _该指令涉及的内存_
的Cache,因此barrier就能保证所有CPU的Cache一致性。

 lock前缀(或cpuid、xchg等指令)使得本CPU的Cache写入了内存,该写入动作也会引起别的CPU invalidate其Cache。
IA32在每个CPU内部实现了Snoopying(BUS-Watching)技术,监视着总线上是否发生了写内存操作(由某个CPU或DMA控
制器发出的),只要发生了,就invalidate相关的Cache line。 因此,只要lock前缀导致本CPU写内存,就必将导致
所有CPU去invalidate其相关的Cache line。 ”


内存屏障的概念很好理解,不同硬件实现内存屏障的方式不同,Java内存模型屏蔽了这种底层硬件平台的差异,由JVM来为不同的平台生成相应的机器码。


看一下volatile的实现

有些材料里说Java实现volatile的时候使用了类似mfence等内存屏障,但是我经过测试发现在X86平台上volatile是用Lock前缀来实现的,测试的是JDK6和7。

下面来看一下volatile生成的汇编码

写volatile的时候生成汇编码是 lock addl $0x0, (%rsp), 在写操作之前使用了lock前缀,锁住了总线和对应的地址,这样其他的写和读都要等待锁的释放。当写完成后,释放锁,把缓存刷新到主内存。

1. 读volatile就很好理解了,不需要额外的汇编指令,CPU发现对应地址的缓存被锁了,等待锁的释放,缓存一致性协议会保证它读到最新的值。 

2. 只需要对写volatile的使用用lock对总线加锁就行了,这样其他的读、写操作等待总线释放才能继续读。Lock会让其他CPU的缓存invalide,从内存重新加载数据。


再看一下synchronized的实现。synchronized块生成JVM指令是monitorenter, monitorexit,最后生成的汇编指令是

lock cmpxchg %r15, 0x16(%r10)  和 lock cmpxchg %r10, (%r11)


cmpxchg是CAS的汇编指令,这里的含义是先用lock指令对总线和缓存上锁,然后用cmpxchg CAS操作设置对象头中的synchronized标志位。CAS完成后释放锁,把缓存刷新到主内存。

所以synchronized的底层操作含义是先对对象头的锁标志位用lock cmpxchg的方式设置成“锁住“状态,释放锁时,在用lock cmpxchg的方式修改对象头的锁标志位为”释放“状态,写操作都立刻写回主内存。JVM会进一步对synchronized时CAS失败的那些线程进行阻塞操作,这部分的逻辑没有体现在lock cmpxchg指令上,我猜想是通过某种信号量来实现的。lock cmpxchg指令前者保证了可见性和防止重排序,后者保证了操作的原子性。



参考资料:

Memory Barriers/Fences

LOCK vs MFENCE

Memory barrier

多处理器多线程使用_asm lock指令能保证互斥吗?

聊聊高并发(十八)理解AtomicXXX.lazySet方法 看过java.util.concurrent.atomic包里面各个AtomicXXX类实现的同学应该见过lazySet方法,比如AtomicBoolean类的lazySet方法 public final void lazySet(boolean newValue) { int v = newValue ? 1 : 0; unsafe.putOrderedInt( 阅读详情

相关推荐

Zynq 双核AMP 通信

4、配置离线编译(这里不讲),配置linux的内核地址空间(0x4000_0000改为0x2000_0000),以及单核启动。CPU1设置为0x2000_0000~0x3FFF_FFFF(也可以小于0x3FFF_FFFF)如果禁用CPU1的L2 cache,在CPU1的bsp里面添加编译时候所需要的宏。3、配置工程,将vivado产生的.xsa文件复制到amp_com项目目录下。9、使用petalinux-package --boot 打包。一、vivado工程。5、编译u-boot。

y183128184的博客 1086

深入理解Java的内存屏障

本文主要介绍了Java中的内存屏障相关知识,包括内存屏障的概念、分类、工作原理、应用场景和样例代码等。通过本文的学习,读者可以更好地理解Java中内存模型的工作原理,进而编写出更加高效、可靠的多线程程序。同时,读者也可以进一步了解JDK中提供的各种并发工具,从而更好地利用Java中的多线程机制来提升代码的性能和稳定性。

grandachn的博客 1065

量子密钥分发系统的设计与实现(二):光路子系统初步讨论

本文主要对量子密钥分发系统中的光路子系统方案进行了讨论。

量子领域相关话题 2406

Volatile关键字底层Lock指令和内存屏障简单介绍

对Volatile关键字修饰的变量,执行写操作的时候,Jvm会发送一条lock前缀指令给CPU,CPU在操作完这个变量后会立即把这个值写会主存中,同时有MESI缓存一致性协议,所以各个CPU都会对总线进行嗅探,感知自己本地高速缓存区中的数据是否被其他线程修改过。如果发现本地缓存的数据被其他线程修改,那么本地高速缓存区与主存中不一致的数据当做过期的值并清理掉。然后再从主存内中重新加载最新的数据

qq_18565879的博客 1348

STM32 CubeMX实战:手把手教你用I2C驱动IST8310磁力计(附完整代码)

本文详细介绍了如何使用STM32 CubeMX和I2C驱动IST8310磁力计,从硬件连接到代码实现的完整流程。重点讲解了I2C通信异常处理、传感器初始化序列优化以及中断驱动数据采集方案,帮助开发者快速搭建可靠的地磁场数据采集系统。

weixin_42531163的博客 189

使用 ONLYOFFICE API 构建 Java 转换器,在 Word 和 PDF 之间进行转换

随着文档处理需求的增加,格式转换成为了一个重要的需求点。由于PDF格式具有跨平台、不易被篡改的特性,将Word格式(.docx)转换为PDF格式(.pdf)的需求尤为强烈。ONLYOFFICE作为一个强大的办公套件,提供了这样的转换功能,使得用户可以轻松地在Word和PDF之间进行转换。

ONLYOFFICE的官方博客 4569

DS90UB940 解串器芯片及驱动分析

        DS90UB940为解串器,在整个投屏传输通路中起到开关作用。在未与同轴电缆上输入信号的时钟同步前(可能未连接,也可能连接后时钟未同步),LOCK引脚和PASS引脚均为高阻态,电气特性呈现为高电平,没有数据输出。时钟同步后,LOCK引脚输出1,可以正常输出数据。PASS引脚则用于检测输入信号的时序(比如DE length、VSync length)是否有异常;输出1表示OK,输出0...

一墨的博客 8727

Ansys Zemax与Speos协同设计:从HUD光学优化到驾驶环境可视化全流程解析

本文深入解析了如何利用Ansys Zemax与Speos进行协同设计,实现从HUD光学系统核心优化到驾驶环境可视化验证的全流程。文章强调了HUD设计是光学性能与视觉感知的深度耦合,通过Zemax进行精密光学设计,再利用Speos进行系统级仿真与感知模拟,最终完成从虚拟到现实的闭环验证,有效提升HUD产品的开发效率与可靠性。

weixin_29199873的博客 243

volatile实现解析

反汇编生成代码 使用测试代码,观察value值生成的汇编代码: volatile int value = 1; @Test public void test() { value++; } 反汇编观察value++时候的代码: 0x000000011541f775: lock addl $0x0,(%rsp) ;*putfield queue addl操作前面,会加入一个lock前缀指令。 下面来查询lock前缀指令的作用:lock 描述翻译: lo

我们的征途是星辰大海 1014

细聊Oracle通过ODBC数据源连接SQL Server数据库

    类似文章搜索引擎上有很多,内容大致相同,今天所谓细聊是因为我在借鉴这些文章时候走了些弯路,所以写此文,为自己备忘,同时如果能为初涉此处知识点的小伙伴提供些帮助就更好了,废话不多说。    我的应用场景:    项目系统使用oracle数据库,与客户的第三方系统供应商实现资源共享,对方为sql server数据库;    我的测试开发环境为64bitwin7PC机,本机上装有64位Oracl...

xueren_83的博客 1万+

几何非线性-屈曲分析

结构系统的破坏分为两种,一类是因材料软化而引起的强度破坏,另一类是几何软化使得结构的几何形状发生极大变化,从而使结构丧失承载能力。在材料力学中是这样定义压杆失稳的:中心受压直杆(理想模型)在直线状态下平衡,由稳定平衡转化为不稳定平衡时所受的轴向压力的界限值,称为临界压力。中心受压直杆在临界压力的作用下,其直线形态的平衡开始丧失稳定性,简称为失稳。显然,这个定义只使用于理想的压杆模型,那么关于失稳和屈曲是否存在一般性定义呢?

YORU_NO_KUNI的博客 1万+

聊聊高并发(三十六)Java内存模型那些事(四)理解Happens-before规则

在前几篇将Java内存模型的那些事基本上把这个域底层的概念都解释清楚了,聊聊高并发(三十五)Java内存模型那些事(三)理解内存屏障 这篇分析了在X86平台下,volatile,synchronized, CAS操作都是基于Lock前缀的汇编指令来实现的,关于Lock指令有两个要点: 1. lock会锁总线,总线是互斥的,所以lock后面的写操作会写入缓存和内存,可以理解为在lock后面的写缓存

ITer_ZC的专栏 7583

MySQL等保三级合规实践:如何安全配置root账户的本地与受信主机登录策略

本文详细介绍了MySQL在等保三级合规框架下如何安全配置root账户的本地与受信主机登录策略。通过分析root账户的特殊保护需求,提供三种安全加固方案,包括限制访问范围、限定登录IP和完全禁止远程登录,并指导创建安全的远程管理账户。文章还涵盖了密码策略强化、日志审计配置和网络层防护等关键合规要求,帮助用户实现MySQL的等保三级全面合规。

weixin_42522964的博客 259

Java内存模型

Java内存模型(JMM)的介绍 在上一篇文章中总结了线程的状态和基本操作,对多线程已经有一点基本的认识了,如果多线程编程只有这么简单,那我们就不必费劲周折的去学习它了。在多线程中稍微不注意就会出现线程安全问题,那么什么是线程安全问题?我的认识是,在多线程下代码执行的结果与预期正确的结果不一致,该代码就是线程不安全的,否则是线程安全的。虽然这种回答似乎不能获取什么内容,可以google下。在&lt...

ThinkWon的博客 1万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

聊聊高并发(三十四)Java内存模型那些事(二)理解CPU高速缓存的工作原理

在上一篇聊聊高并发(三十三)从一致性(Consistency)的角度理解Java内存模型 我们说了Java内存模型是一个语言级别的内存模型抽象,它屏蔽了底层硬件实现内存一致性需求的差异,提供了对上层的统一的接口来提供保证内存一致性的编程能力。 在一致性这个问题域中,各个层面扮演的角色大致如下: 1. 一致性模型,定义了各种一致性模型的理论基础 2. 硬件层,提供了实现某些一致性模型的硬件能力

ITer_ZC的专栏 1万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

三、聊聊并发 - 聊聊我对Java内存模型的认识

文章目录前言什么是Java内存模型JMM对并发问题的解决方案Java内存模型分析DCL内存模型对于原子性的保证内存模型之Happens-befor内存模型之as-if-serial内存模型之volatileJMM对于volatile读写的规则定义:JMM对volatile变量重排序规则定义:JMM是如何实现volatile的语义规则可见性的实现有序性的实现内存模型之finalfinal域写重排序规...

livolador’s blog 964

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

聊聊高并发(三十三)Java内存模型那些事(一)从一致性(Consistency)的角度理解Java内存模型

可以说并发系统要解决的最核心问题就是一致性的问题,关于一致性的研究已经有几十年了,有大量的理论,算法支持。这篇说说一致性这个主题一些经常提到的概念,理清Java内存模型在其中的位置。 一致性问题在单机器单CPU的情况下是最简单的,由于只有一个CPU,所有的读写操作都可以按照全局的时间顺序执行 在单机器多CPU的情况下,多CPU并发执行,公用一个内存,一般通过共享内存的方式来处理一致性问

ITer_ZC的专栏 1万+

聊聊Hotspot内存屏障如何禁止指令重排

JVM的内存模型,也就是Java内存模型(Java Memory Model,JMM),主要是围绕在并发过程中如何处理原子性、可见性和有序性这三个特性来建立的模型。在Java中,所有实例域、静态域和数组元素都存储在堆内存中,并且在多个线程之间共享。本地变量、方法定义的参数以及异常处理器参数不会在线程之间共享,它们不会有数据竞争的问题。线程对这些共享数据的操作必须通过主内存来协调。线程之间不能直接通信,线程对共享数据的所有读写都必须通过主内存进行。

日拱一卒无有尽,功不唐捐终入海 459

java final 内存_聊聊 Java 内存模型

原标题:聊聊 Java 内存模型*作者:青芒@有赞本文目录Java内存模型重排序内存屏障volatitle的内存语义final的内存语义一、Java内存模型硬件处理电脑硬件,我们知道有用于计算的cpu、辅助运算的内存、以及硬盘还有进行数据传输的数据总线。在程序执行中很多都是内存计算,cpu为了更快的进行计算会有高速缓存,最后同步至主内存,大概的交互如下图 为了使处理器内部的运算单元能够被充分的利用...

weixin_42513269的博客 296

java内存模型 final_聊聊Java内存模型

一、Java内存模型硬件处理电脑硬件,我们知道有用于计算的cpu、辅助运算的内存、以及硬盘还有进行数据传输的数据总线。在程序执行中很多都是内存计算,cpu为了更快的进行计算会有高速缓存,最后同步至主内存,大概的交互如下图为了使处理器内部的运算单元能够被充分的利用,处理器可能会对输入代码进行乱序执行优化,然后将计算后的结果进行重组,保证该结果和顺序执行的结果是一致的(单位时间内,一个core只能执行...

weixin_42508290的博客 134

聊聊 Java 内存模型

*作者:青芒@有赞本文目录Java内存模型重排序内存屏障volatitle的内存语义final的内存语义一、Java内存模型硬件处理电脑硬件,我们知道有用于计算的cpu、辅助运算的内存、以及硬盘还有进行数据传输的数据总线。在程序执行中很多都是内存计算,cpu为了更快的进行计算会有高速缓存,最后同步至主内存,大概的交互如下图为了使处理器内部的运算单元能够被充分的利用,处理器可能会对输入代码进行乱序执...

weixin_44742132的博客 98

电商系统开发中的Java内存模型实战

不要过早优化,先保证正确性再考虑性能线程数超过CPU核心数时,上下文切换成本会显著上升使用ThreadLocal存储线程专属变量能减少争用长期运行的系统要注意内存泄漏,特别是静态集合的使用这次开发让我意识到,理解JMM不仅能解决眼前问题,更能预防潜在的并发隐患。推荐使用InsCode(快马)平台来快速验证这类并发场景,它的在线Java环境和一键部署功能特别适合做压力测试和方案对比。

StarfallRaven13的博客 861

Java内存模型相关面试题

volatile解决了多个线程之间的可见性,那volatile是如何做到的呢,咱们继续使用下面这个流程图来讲解,假设线程2比线程1慢执行,当线程1已经进行完data++并写入到主内存时,会将其他有使用到data的线程内保存的变量副本设置成失效状态,此时如果线程2正要去use data变量,发现data变量此时为失效状态,那么就会重新去主内存中读取data,这就做到了data的可见性。线程2是同样的操作,其实Java内存模型主要的操作就是下图中的6个流程,还有另外两个是lock和unlock;

web13524385009的博客 1337
上一篇: Java内存模型Cookbook(二)内存屏障
下一篇: 深入Java底层:内存屏障与JVM并发详解(1)
还不够
博客等级 码龄16年 113粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值