Java并发——volatile

CPU的内存模型如下:
这种模式下,存在多核间缓存数据不一致的问题。为了解决这种问题,有2种硬件策略。
1.当一个CPU从主存读取缓存数据时,总线阻塞;
2.基于缓存一致性协议,当一个CPU读取到共享缓存时,如果某个CPU对共享缓存发生变更操作,会通知其它CPU缓存无效,触发其它CPU重新读主存。
 
JMM抽象的内存模型如下:
JMM是对硬件平台内存模型的抽象。
这个模型解释了JVM在内存中存取变量的动作。
因为只是对底层的抽象,出于性能考虑,存在一致性与指令重排等一些问题。解决这些问题有如下策略:
1.基于内存屏障,在读写共享变量的前后加入相应的屏障指令,阻止共享变量前后的指令重排;
2.基于缓存一致性协议,确保共享变量的写会及时通知所有的CPU。
 
内存屏障分类如下:
 
JMM定义的指令重排序规则:
 
volatile基于内存屏障来保证可见性与阻止指令重排(HB关系)。
  • 在每个volatile写操作的前面插入一个StoreStore屏障;
  • 在每个volatile写操作的后面插入一个StoreLoad屏障;
  • 在每个volatile读操作的后面插入一个LoadLoad屏障;
  • 在每个volatile读操作的后面插入一个LoadStore屏障。
StoreStore屏障:禁止上面的普通写和下面的volatile写重排序
StoreLoad屏障:防止上面的volatile写与下面可能有的volatile读/写重排序
LoadLoad屏障:禁止下面所有的普通读操作和上面的volatile读重排序
LoadStore屏障:禁止下面所有的普通写操作和上面的volatile读重排序
 
 
 
从volatile引申出一个伪共享的问题。
现在大部分计算机的缓存行是64个字节的,当多线程修改相互独立的变量时,如果这些变量共享同一个缓存行,就会影响彼此的性能。
如下图所示:

 

core1和core2修改同一个缓存行的不同变量,需要竞争缓存行的所有权,这种竞争会带来性能损耗。

在Java8中,要避免这种伪共享,可以如下配置:

1.在jvm参数上增加:-XX:-RestrictContended

2.在类,或者字段上增加注解:@Contended

 

 
 
参考:
posted @ 2019-11-13 11:36  飞昂之雪  阅读(208)  评论(0编辑  收藏  举报