为什么会有内存屏障呢_内存出问题有什么现象

为什么会有内存屏障呢_内存出问题有什么现象复习一下内存屏障主要解决指令重排和可见性,需要了解JMM架构原文链接为什么会有内存屏障每个CPU都会有自己的缓存(有的甚至L1,L2,L3),缓存的目的就是为了提高性能,避免每次都要向内存取。但是这样的弊端也很明显:不能实时的和内存发生信息交换,分在不同CPU执行的不同线程对同一个变量的缓存值不同。用volatile关键字修饰变量可以解决上述问题,那么volatile是如何做到这一点的呢?那就是内存屏障,内存屏障是硬件层的概念,不同的硬件平台实现内存屏障的手段并不是一样,java通过屏蔽这些差异,统

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

复习一下内存屏障主要解决指令重排和可见性,需要了解JMM架构
原文链接
为什么会有内存屏障
每个CPU都会有自己的缓存(有的甚至L1,L2,L3),缓存的目的就是为了提高性能,避免每次都要向内存取。但是这样的弊端也很明显:不能实时的和内存发生信息交换,分在不同CPU执行的不同线程对同一个变量的缓存值不同。
用volatile关键字修饰变量可以解决上述问题,那么volatile是如何做到这一点的呢?那就是内存屏障,内存屏障是硬件层的概念,不同的硬件平台实现内存屏障的手段并不是一样,java通过屏蔽这些差异,统一由jvm来生成内存屏障的指令。
内存屏障是什么
硬件层的内存屏障分为两种:Load Barrier 和 Store Barrier即读屏障和写屏障。
内存屏障有两个作用:
阻止屏障两侧的指令重排序;
强制把写缓冲区/高速缓存中的脏数据等写回主内存,让缓存中相应的数据失效。
对于Load Barrier来说,在指令前插入Load Barrier,可以让高速缓存中的数据失效,强制从新从主内存加载数据;
对于Store Barrier来说,在指令后插入Store Barrier,能让写入缓存中的最新数据更新写入主内存,让其他线程可见。
java内存屏障
java的内存屏障通常所谓的四种即LoadLoad,StoreStore,LoadStore,StoreLoad实际上也是上述两种的组合,完成一系列的屏障和数据同步功能。
LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能
volatile语义中的内存屏障
volatile的内存屏障策略非常严格保守,非常悲观且毫无安全感的心态:
在每个volatile写操作前插入StoreStore屏障,在写操作后插入StoreLoad屏障;
在每个volatile读操作前插入LoadLoad屏障,在读操作后插入LoadStore屏障;

由于内存屏障的作用,避免了volatile变量和其它指令重排序、线程之间实现了通信,使得volatile表现出了锁的特性。
final语义中的内存屏障
对于final域,编译器和CPU会遵循两个排序规则:
新建对象过程中,构造体中对final域的初始化写入和这个对象赋值给其他引用变量,这两个操作不能重排序;
初次读包含final域的对象引用和读取这个final域,这两个操作不能重排序;(意思就是先赋值引用,再调用final值)
总之上面规则的意思可以这样理解,必需保证一个对象的所有final域被写入完毕后才能引用和读取。这也是内存屏障的起的作用:
写final域:在编译器写final域完毕,构造体结束之前,会插入一个StoreStore屏障,保证前面的对final写入对其他线程/CPU可见,并阻止重排序。
读final域:在上述规则2中,两步操作不能重排序的机理就是在读final域前插入了LoadLoad屏障。
X86处理器中,由于CPU不会对写-写操作进行重排序,所以StoreStore屏障会被省略;而X86也不会对逻辑上有先后依赖关系的操作进行重排序,所以LoadLoad也会变省略。

转自: https://www.jianshu.com/p/2ab5e3d7e510

JMM模型
JMM 全称是 Java Memory Model. 什么是 JMM 呢? 通过前面的分析发现,导致可见性问题的根本原因是缓存 以及重排序。 而 JMM 实际上就是提供了合理的禁用缓存 以及禁止重排序的方法。所以它最核心的价值在于解决可 见性和有序性。

它解决了 CPU 多级缓存、处理器优化、指令重排序 导致的内存访问问题,保证了并发场景下的可见性。
需要注意
JMM 并没有限制执行引擎使用处理器的寄 存器或者高速缓存来提升指令执行速度,也没有限制编译 器对指令进行重排序,也就是说在 JMM 中,也会存在缓存 一致性问题和指令重排序问题。只是 JMM 把底层的问题抽 象到 JVM 层面,再基于 CPU 层面提供的内存屏障指令, 以及限制编译器的重排序来解决并发问题

JMM 抽象模型分为主内存、工作内存;主内存是所有线程 共享的,一般是实例对象、静态字段、数组对象等存储在 堆内存中的变量。工作内存是每个线程独占的,线程对变 量的所有操作都必须在工作内存中进行,不能直接读写主 内存中的变量,线程之间的共享变量值的传递都是基于主 内存来完成

Java 内存模型底层实现可以简单的认为:通过内存屏障 (memory barrier)禁止重排序,即时编译器根据具体的底层 体系架构,将这些内存屏障替换成具体的 CPU 指令。对 于编译器而言,内存屏障将限制它所能做的重排序优化。 而对于处理器而言,内存屏障将会导致缓存的刷新操作。 比如,对于 volatile,编译器将在 volatile 字段的读写操作 前后各插入一些内存.

JMM 是如何解决可见性有序性问题的
简单来说,JMM 提供了一些禁用缓存以及进制重排序的方 法,来解决可见性和有序性问题。这些方法大家都很熟悉: volatile、synchronized、final.等.

从源代码到最终执行的指令,可能会经过三种重排序。

编译器的重排序,JMM 提供了禁止特定类型的编译器重排 序。
处理器重排序,JMM 会要求编译器生成指令时,会插入内 存屏障来禁止处理器重排序
在这里插入图片描述
另一篇不错的CAS算法博客

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/168680.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python-回文字符串[通俗易懂]

    python-回文字符串[通俗易懂]回文字符串(10分)题目内容:给定一个字符串,判断它是否是回文字符串(即类似于peep,12321这样的对称字符串),如果是输出True,不是则输出False。判断过程中假定只考虑字母和数字字符,而且忽略字母的大小写和其它符号(如空格、标点符号等)。 输入格式:共一行,为一个字符串。 输出格式:共一行,为True或False。 输入样例: lo…

    2022年6月2日
  • load average信息详解

    load average信息详解一、什么是loadaverage?linux系统中的Load对当前CPU工作量的度量(WikiPedia:thesystemloadisameasureoftheamountofworkthatacomputersystemisdoing)。也有简单的说是进程队列的长度。LoadAverage就是一段时间(1分钟、5分钟、15分钟)内平均L

    2022年7月17日
  • idea上git提交忽略部分目录

    idea上git提交忽略部分目录idea上git提交忽略部分目录

    2022年4月24日
  • Ubuntu修改密码和用户名

    Ubuntu修改密码和用户名​Ubuntu是一个Linux操作系统,修改密码和用户名是有危险的动作,请谨慎修改。一、Ubuntu修改密码和用户名Ubuntu更改密码步骤:1、进入Ubuntu,打开一个终端,输入sudosu转为root用户。注意,必须先转为root用户!!!2、sudopasswduser(user是对应的用户名)3、输入新密码,确认密码。4、修改密码成功,重启,输入新密码进入Ubun…

    2022年9月29日
  • mysql导入数据库_只用frm向mysql导入表结构

    网上一个连接mysql的jsp代码段,给了数据库的备份文件,但是只有frm,查了下资料,原来只有frm也能导入。 过程如下:1.在mysql目录下的data目录中,找到要导入表所在的数据库的名称,把frm文件放进去,比如我这里是offer.frm,数据库名称是netshop,放到数据库netshop目录下之后,在mysql中show tables显示如下在这里table是显示的,但是desc of

    2022年3月11日
  • 一叶知秋,一个 LED 就能入门 Linux 内核「建议收藏」

    一叶知秋,一个 LED 就能入门 Linux 内核「建议收藏」简单点灯最近项目上需要用到LED子系统,在嵌入式Linux里面点个灯还是比较简单的,只要在某个灯对应的目录里,向相应文件写入特定值,就可以让LED亮/灭/闪烁。#echo1>/sys/class/leds/green/brightness//点亮LED#echo0>/sys/class/leds/green/brightness//熄灭LED#echoheartbeat>/sys/class/leds/green/trigger//

    2022年7月16日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号