• 内存屏障


    编译器和处理器必须同时遵守重排规则。多核处理器需使用内存屏障指令来确保一致性。即使编译器优化掉了一个字段访问(因为一个读入的值未被使用),需要产生内存屏障,就像这个访问仍然需要保护。(可参考下面的优化掉内存屏障的章节)。

    内存屏障指令仅直接控制CPU与其缓存之间,与垃圾回收机制中“写屏障(write barriers)”无关。

    一、重排序

    编译器或者CPU的代码的结构重排排序,达到最佳效果。

    (1)编译器重排

     
     

    CPU只读一次的x和y值。不需反复读取寄存器交替x和y值

    (2)处理器重排

     
     
     
     

    写缓存区没有及时刷新,使得处理器执行的读写操作与内存上顺序不一致

    处理器A读b=0,处理器B读a=0。A1写a=1先写到处理器A的写缓存区中,此时内存中a=0。如果这时处理器B从内存中读a,读到的将是0。

    可能会出现x,y都是0。

     
     

    二、内存屏障

    为了解决上述问题,处理器提供内存屏障指令(Memory Barrier):

    写内存屏障(Store Memory Barrier):处理器将存储缓存值写回主存(阻塞方式)。

    读内存屏障(Load Memory Barrier):处理器,处理失效队列(阻塞方式)。

     
     

    保证两个操作之间数据的可见性。

    volatile读前插读屏障,写后加写屏障,避免CPU重排导致的问题,实现多线程之间数据的可见性

    三、内存屏障的种类

    StoreLoad开销最大。万能屏障,兼具其它三种内存屏障功能。执行时,处理器通常要把写缓冲区中的数据全部刷新的内存中

     
     

    对于处理器来说,内存屏障会导致cpu缓存的刷新,刷新时,会遵循缓存一致性协议。

    lock

    解锁时,jvm会强制刷新cpu缓存,导致当前线程更改,对其他线程可见。

    volatile

    (1)对于写操作:对变量更改完之后,要立刻写回到主存中。

    (2)对于读操作:对变量读取的时候,要从主存中读,而不是缓存。

    final:即时编译器在final写操作后,会插入内存屏障,来禁止重排序,保证可见性

  • 相关阅读:
    Git 操作
    SVN
    一维数组
    常见的数学方法
    常用事件
    function函数
    while;do while; for循环
    JS中的变量提升
    关于js的单双引号嵌套问题
    db.collection is not a function
  • 原文地址:https://www.cnblogs.com/anhaogoon/p/13177605.html
Copyright © 2020-2023  润新知