• JVM学习——3——数据一致性


    一、硬件层数据一致性

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

    1. 缓存一致性协议

    缓存一致性协议 英特尔MESI
    有很多缓存一致性协议
    通过这个协议让各个CPU中的缓存数 据一致
    cpu每个cache line标记四种状态
    MESI
    Modified 标记为修改
    Exclusive 标记为独享
    Shared 标记为共享
    Invalid 标记为我读的时候被别的CPU改过
    缓存锁实现之一,有些无法被缓存的数据,或者跨越多个缓存行(数据太大,一个缓存行64KB装不下)的数据依然必须使用总线锁 (同时只有一个CPU能访问内存)

    2. 缓存行cache line

    使用缓存行对齐可以减少伪共享来提高效率

    多为64字节
    读取的时候以缓存行为基本单位
    例如int占4字节,我只要读一个int值,但我会读一整行,会把后面的long类型的数据一起读进来
    如果一个CPU只要读这个int值,这个long值也会被读进来;
    同时另一个CPU读long值,也会把int值读进来
    如果x被修改,则会通知其他使用本缓存行的CPU,让它重新读这一行,同理,long数据被修改后,另一个使用这行的CPU也要重读。 这个现象叫 “ 伪共享 ” ;两个毫无关联的数据因为在同一行搁这儿变来变去的。
    缓存行对齐 cache line padding
    补充long类型,一行64KB,补充7个long类型 + 1个int
    补充7个long类型 + 1个long类型
    这样两个数据就不在一行中,就不会伪共享一直刷新
    在disrupt这个最快的消息队列中有这样用
    进入到JAVA8后,官方已经提供了对伪共享的解决办法,那就是@sun.misc.Contended注解,加在类上,有了这个注解解决伪共享就变得简单多了
    默认情况下此注解是无效的,需要在JVM启动时设置-XX:-RestrictContended

    二、乱序问题

    CPU为了提高指令执行效率,会在一套指令执行过程中(比如cpu比去内存读快100倍)去执行另一头指令,前提是这两个指令没有依赖关系
    比如 int a=11
    int b=a
    这种就会乱序
    int a=1
    a=2
    int b=3
    可能会乱序
    读指令的同时也可以执行不影响的其他指令
    而写的同时也可以进行 合并写 WCBiffer 这个缓冲区只有4字节
    写操作也可以合并

    2.1 有序性保障(X86的CPU是依靠内存屏障)

    加CPU级别的内存屏障
    savefence 存屏障 写指令
    sfence : 在sfence指令前的写操作 必须 在 sfence指令后的写操作前完成
    loadfence 读屏障 读指令
    lfence:在lfence指令前的读操作 必须 在lfence指令后的读操作前完成
    混合的 mix 读写屏障 全能屏障
    mfence:在mfence指令前的写操作 必须 在mfence指令后的读写操作前完成
    volatile前后都加了屏障
    x86的lock指令也可以实现内存屏障,可以跨越多个CPU
    Java的内存屏障 Load Store是基于CPU的指令实现的
    A Load Load B A 读完 B才能读
    A Load Store B A 读完 B才能写
    A Store Store B A 写完B才能写
    A Store Load B A 写完B才能写

  • 相关阅读:
    阿里云短信服务设置操作项目
    Alibaba Druid整合
    EM聚类(上):数据分析 | 数据挖掘 | 十大算法之一
    浙政钉用户登陆
    WebRTC系列--sdp协商中的answer编解码协商过程
    民安智库(第三方市场调研公司)保障性住房满意度调查流程
    【Azure Developer - 密钥保管库 】使用 Python Azure SDK 实现从 Azure Key Vault Certificate 中下载证书(PEM文件)
    备忘录模式
    Vue详解及综合案例
    怎么使用下载视频号视频?详细视频下载使用教程
  • 原文地址:https://blog.csdn.net/niTaoTaoa/article/details/126273467