Java内存屏障-JMM

  • Java内存屏障和JMM
    • 硬件层数据一致性
      • 伪共享
    • 乱序问题
    • 如何保证特定情况下不乱序
      • volatile的实现细节
      • synchronized实现细节

Java内存屏障和JMM

硬件层数据一致性

协议很多

intel 用MESI

https://www.cnblogs.com/z00377750/p/9180644.html

现代CPU的数据一致性实现 = 缓存锁(MESI …) + 总线锁

伪共享

读取缓存以cache line为基本单位,目前64bytes

位于同一缓存行的两个不同数据,被两个不同CPU锁定,产生互相影响的伪共享问题

代码演示

package com.cyc.juc.c_028_FalseSharing;import java.util.Random;/*** 模拟位于同一缓存行的两个不同数据,被两个不同CPU锁定,产生互相影响的伪共享问题* arr数组中有T对象,长度为2, 开启两个线程, 循环的同时给a0和a1赋值,t1线程只给a0赋值, 但是却要拿到整个* arr数组,t2给a1赋值, 同样, 拿到的也是arr数组, 也就是说他们操作的是同一个对象, t1操作之后, t2拿到的arr要同步t1* 修改过的a0,同理, t1拿到arr之后也要同步t2修改过的a1, 两者在操作之前都要去同步数据,此时效率就降低了很多。*/
public class T01_CacheLinePadding {private static class T {public volatile long x = 0L;}public static T[] arr = new T[2];static {arr[0] = new T();arr[1] = new T();}public static void main(String[] args) throws Exception {Thread t1 = new Thread(()->{for (long i = 0; i < 1000_0000L; i++) {arr[0].x = i;}});Thread t2 = new Thread(()->{for (long i = 0; i < 1000_0000L; i++) {arr[1].x = i;}});final long start = System.nanoTime();t1.start();t2.start();t1.join();t2.join();System.out.println((System.nanoTime() - start)/100_0000);}
}

连续三次的输出结果为: 238, 214, 273

使用缓存行的对齐能够提高效率

代码演示

package com.mashibing.juc.c_028_FalseSharing;/*** 由于一个缓存行占64个字节, 因此Padding中预设7个基本数据类型,每个数据类型占8个字节,共计56个字节,* 这些数据不做任何操作,只是为了占位和保持行对齐* 新建的T对象继承Padding, 此时每个T对象保证可以是在不同的缓存行中,从而避免相互影响*/
public class T02_CacheLinePadding {private static class Padding {public volatile long p1, p2, p3, p4, p5, p6, p7;}private static class T extends Padding {public volatile long x = 0L;}public static T[] arr = new T[2];static {arr[0] = new T();arr[1] = new T();}public static void main(String[] args) throws Exception {Thread t1 = new Thread(()->{for (long i = 0; i < 1000_0000L; i++) {arr[0].x = i;}});Thread t2 = new Thread(()->{for (long i = 0; i < 1000_0000L; i++) {arr[1].x = i;}});final long start = System.nanoTime();t1.start();t2.start();t1.join();t2.join();System.out.println((System.nanoTime() - start)/100_0000);}
}

连续三次执行的结果耗时: 69, 69, 70

可以看到, 执行速度有了很大的提升, 虽然多占据了一些空间, 但是比起节省的时间, 还是值得的。

乱序问题

CPU为了提高指令执行效率,会在一条指令执行过程中(比如去内存读数据(慢100倍)),去同时执行另一条指令,前提是,两条指令没有依赖关系

https://www.cnblogs.com/liushaodong/p/4777308.html

写操作也可以进行合并

https://www.cnblogs.com/liushaodong/p/4777308.html

JUC/029_WriteCombining

乱序执行的证明:JVM/jmm/Disorder.java

原始参考:https://preshing.com/20120515/memory-reordering-caught-in-the-act/

如何保证特定情况下不乱序

硬件内存屏障 X86

sfence: store| 在sfence指令前的写操作当必须在sfence指令后的写操作前完成。
lfence:load | 在lfence指令前的读操作当必须在lfence指令后的读操作前完成。
mfence:modify/mix | 在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。

原子指令,如x86上的”lock …” 指令是一个Full Barrier,执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU。Software Locks通常使用了内存屏障或原子指令来实现变量可见性和保持程序顺序

JVM级别如何规范(JSR133)

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的实现细节

  1. 字节码层面
    ACC_VOLATILE

查看其字节码文件, 通过对比,可以看到 volatile修改的变量在字节码层面添加了个volatile标识。

  1. JVM层面
    volatile内存区的读写 都加屏障

    StoreStoreBarrier

    volatile 写操作

    StoreLoadBarrier

    LoadLoadBarrier

    volatile 读操作

    LoadStoreBarrier

  2. OS和硬件层面
    https://blog.csdn.net/qq_26222859/article/details/52235930
    hsdis - HotSpot Dis Assembler
    windows lock 指令实现 | MESI实现

synchronized实现细节

  1. 字节码层面
    ACC_SYNCHRONIZED
    monitorenter monitorexit

  1. JVM层面
    C C++ 调用了操作系统提供的同步机制
  2. OS和硬件层面
    X86 : lock cmpxchg / xxx
    https

    JVM---Java内存屏障和JMM相关推荐

    1. JVM——Java内存模型(JMM)

      关注微信公众号:CodingTechWork,一起学习进步. 软硬件发展概述 Amdahl定律和摩尔定律 1)Amdahl定律:通过系统中并行化和串行化的比重来描述多处理器系统能获得的运算加速能力. ...

    2. JVM(一)JVM虚拟机内存结构 和 JAVA内存模型(JMM)

      本文转自:浅析java内存模型--JMM(Java Memory Model) - 路易小七 - 博客园,尊重作者,转载请注明出处~ JVM虚拟机内存结构 和 JAVA内存模型 是两个不同的概念 JV ...

    3. 高并发编程-通过volatile重新认识CPU缓存 和 Java内存模型(JMM)

      文章目录 概述 volatile定义 CPU缓存 相关CPU术语 CPU缓存一致性协议MESI 带有高速缓存的CPU执行计算的流程 CPU 多级的缓存结构 Java 内存模型 (JMM) 线程通信的两 ...

    4. java内存屏障的原理与应用

      目录 1. java内存屏障 2.java内存屏障的使用 一. java内存屏障 1.1 什么是内存屏障(Memory Barrier)? 内存屏障(memory barrier)是一个CPU指令.基 ...

    5. java内存屏障_java内存屏障

      java内存屏障 java的内存屏障通常所谓的四种即LoadLoad,StoreStore,LoadStore,StoreLoad实际上也是上述两种的组合,完成一系列的屏障和数据同步功能. LoadL ...

    6. 20191209知乎之Java内存模型(JMM)总结

      Java内存模型(JMM) 我们常说的JVM内存模式指的是JVM的内存分区:而Java内存模式是一种虚拟机规范. Java虚拟机规范中定义了Java内存模型(Java Memory Model,JMM ...

    7. 高并发编程-重新认识Java内存模型(JMM)

      文章目录 从CPU到内存模型 内存模型如何确保缓存一致性 并发变成需要解决的问题 (原子性.可见性.有序性) 内存模型需要解决的问题 Java内存模型 JMM的API实现 原子性 synchroniz ...

    8. Java内存模型(JMM)详解-可见性volatile

      这里写自定义目录标题 Java内存模型(JMM)详解-可见性 什么是JMM JMM存在的意义 为什么示例demo中不会打印 i 的值 如何解决可见性问题 **深入理解JMM内存模型** JAVA内存模 ...

    9. 内存屏障(cpu内存屏障 与java内存屏障)

      文章目录 CPU 内存屏障 定义 读写屏障指令 为什么会出现内存屏障 java内存屏障 java内存屏障存在意义 java中内存屏障的主要类型 LoadLoad 屏障 StoreStore 屏障 Lo ...

    最新文章

    1. 【spring boot2】第8篇:spring boot 中的 servlet 容器及如何使用war包部署
    2. 比特币前核心开发者Mike Hearn三年前的预测一一应验
    3. php-fpm进程关闭与重启脚本详解(转)
    4. 图解用MySQL创建进销存数据库
    5. 2016.07.17-18 集合方法
    6. 使用github pages创建博客
    7. Ubuntu 14.04 安装Visual studio Code
    8. mysql中数据库覆盖导入的几种方式
    9. 前端学习(176):列表元素
    10. 配置多台三层交换VLAN间相互通信
    11. 网络编程(一)基础知识
    12. 【原生态跨平台:ASP.NET Core 1.0(非Mono)在 Ubuntu 14.04 服务器上一对一的配置实现-篇幅2】...
    13. 学计算机专业的需要买电脑吗,高三党升级“准大一生”,有必要买电脑吗?学长的回答可以参考...
    14. Manjaro oh-my-zsh安装配置
    15. acm模板 java_java 之acm模板
    16. 深度学习2.0-19.随机梯度下降之可视化与实战
    17. 区块链 Fisco bcos 智能合约(18)-FISCO BCOS的速度与激情:性能优化方案最全解密
    18. linux开远程连接,Linux/Ubuntu 怎么设置打开远程桌面登录连接
    19. Java复习 思维导图
    20. 图像质量评价(IQA)综述

    热门文章

    1. 计算机许可管理器服务器名称是什么意思,服务器客户端访问许可是什么意思
    2. Android 播放自定义铃声
    3. PHP imagick安装与配置
    4. 最优化方法----powell共轭梯度算法
    5. 改善程序员生活质量的 3+10 习惯
    6. 网络的一些特殊状态网络回路,广播风暴等原因导致网速慢的问题和网络不稳定的问题
    7. win7计算机打开一直在搜索,在win7电脑中打开文件夹却变成了搜索界面怎么办?...
    8. ZZULI—刷题之路
    9. 【 免费域名 】免费域名与阿里云服务器绑定
    10. mediapipe KNN 基于mediapipe和KNN的引体向上计数/深蹲计数/俯卧撑计数【mediapipe】【KNN】【BlazePose】【K邻近算法】【python】