关于volatile

个人总结

volatile 保障了共享变量在工作线程之间的可见性&禁止指令重排。可见性的问题是因为CPU的多级缓存架构导致的,指令重排是为了对程序进行优化导致的。在单线程中是不存在可行性和顺序性的问题, 通俗的讲操作之间如果没有数据依赖性,可以进行任意重拍,不会影响执行结果(as-if-serial语义)。 但是多个线程之间的数据依赖和相互影响编译器&cpu层面无法感知,需要编译器&CPU的上层来决定。 为了解决多线程场景下 可见性和指令重拍的问题, Java引入了 JMM , JMM是一套规范 定义工作内存与主内存的数据交互方式。为了描述这个规范, JMM引入了 happen-before原则,用来描述多个操作之间的内存可见性,顺序性。参考happen-before原则中对volatile的描述可以:volatile关键字要保障 可见性&顺序性。 在JMM层面 volatile 是通过 JMM层面的内存屏障实现的(可以描述一下 JMM层面4个内层屏障,以及在volatile描述的变量前轴都加哪些屏障),再具体到汇编语言层面是通过lock指令实现的。

JMM层面提供的内存屏障:

  • Store:将处理器缓存的数据刷新到内存中。
  • Load:将内存存储的数据拷贝到处理器的缓存中。

LoadLoad : Load1;LoadLoad;Load2 该屏障确保Load1数据的装载先于Load2及其后所有装载指令的的操作
StoreStore: Store1;StoreStore;Store2 该屏障确保Store1立刻刷新数据到内存(使其对其他处理器可见)的操作先于Store2及其后所有存储指令的操作
LoadStore : 确保Load1的数据装载先于Store2及其后所有的存储指令刷新数据到内存的操作
StoreLoad : 该屏障确保Store1立刻刷新数据到内存的操作先于Load2及其后所有装载装载指令的操作。它会使该屏障之前的所有内存访问指令(存储指令和访问指令)完成之后,才执行该屏障之后的内存访问指令

下面是基于保守策略的JMM内存屏障插入策略。
·在每个volatile写操作的前面插入一个StoreStore屏障。
·在每个volatile写操作的后面插入一个StoreLoad屏障。
·在每个volatile读操作的后面插入一个LoadLoad屏障。
·在每个volatile读操作的后面插入一个LoadStore屏障。

posted @ 2021-09-29 22:48  abs_征召不老  阅读(38)  评论(0)    收藏  举报