二、内存屏障简介

124 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

二、内存屏障

写在前面

  • volatile关键字可以保障线程间的可见性、多核情况下防止指令重排
  • volatile通过内存屏障来防止指令重排。JVM在编译volatile关键字修饰的变量时,会加入特定的内存屏障来保证;

JMM 内存屏障主要有 Load 和 Store 两种

  • loadBarrier 读屏障
    • 在读指令之前插入读屏障,让缓存数据失效,如需使用再次从主存读取
  • StoreBarrier:写屏障
    • 在写指令之后,把写完之后的数据刷回主存

内存屏障的一般操作

  • StoreStore 屏障:

    • 在每个volatile写操作前面加入StoreStore 屏障,保证按照顺序吧数据从缓存刷新回主存

    l例如:A,StoreStore,B意味着在B写入操作执行之前,必须先保证A的写入操作先执行完,且写入结果对其他线程可见,禁止StoreStore两边的操作位置乱序;

  • StoreLoad屏障: A,StoreLoad,B

    • 用于在数据读取操作之前,必须完成对数据的写入操作,保证A的写入必须在B读取之前,且A的写入结果对其他处理器可见;
  • LoadLoad屏障:

    • 用于保证对两个读取的顺序保证A读取完成B才能读取,缓存中的数据失效,必须重新从主存中读取;
  • LoadStore屏障

    • 执行在写入操作之前,保证前面的先读取完,才能执行后面的写入;

volatile 写操作的内存屏障

​ 一般而言volatile写操作的内存屏障是 :

在每个 volatile 写操作前插入 StoreStore屏障,在写操作后面插入 StoreLoad 屏障。

SS写屏障的作用为:

----------->SS , volatile写 ,SL<-----------------

  • 两端的指令不会发生乱序问题

  • 在前面的写指令完成之后, 处理器的缓存行数据刷入主存

  • volatile前面的写操作,一定先执行。因为在 volatile 写之前,前面的所有普通写操作已经被刷新到主存。

StoreLoad 屏障作用

  • 前面的写入操作会先执行完成,刷内完成;
  • 前面的写指令完成之后,主存数据刷新完成
  • 后面的读操作,让处理器缓存中的数据失效,重新从主内存加载数据
  • 在 volatile 写完成之后,缓存中的已经刷新成最新数据,线程间可见。

volatile 读操作的内存屏障

volatile 读操作的内存屏障插入策略:

在每个 volatile 写操作后插入 LoadLoad屏障和 LoadStore 屏障

LoadLoad 屏障可以保证

  • 前面的读操不会被排到后面去了;

  • 让高速缓存中的数据失效,重新从主内存加载数据;

  • 后面读操作不会被排到前面去了 ,因此在 volatile 读之后,所高速缓存中的数据是重新从主存加载的,并且是最新数据。

LoadStore 屏障可以保证:

  • 前面的读操不会被排到后面去了;
  • 让高速缓存中的数据失效,重新从主内存加载数据;
  • 后面写操作不会被排到前面去了。
  • 在 volatile 读之后,所高速缓存中的数据是重新从主存加载的,并且是最新数据‘

【参考总结于】Java高并发核心编程