目录
语义描述
写语义:当写一个volatile变量时候,JMM会把该线程对应的本地内存的共享变量直接刷新到主内存中。
读语义:当读一个volatile变量的时候。JMM会把该线程对应的本地内存置为无效,从而从主内存中读取。
重排序规则
是否能重排序 | 第二个操作 | ||
第一个操作 | 普通变量读/写 | volatile变量读 | volatile变量写 |
普通变量读/写 | NO | ||
volatile变量读 | NO | NO | NO |
volatile变量写 | NO | NO |
总结
1. 如果第二个操作是volatile变量的写,则不管第一个操作是什么都不可以重排序
2. 如果第一个变量是volatile变量的读,则不管第二个操作是什么都不可以重排序3. 当第一个操作是volatile变量写,第二个是volatile变量读,则不可以重排序
JMM如何实现volatile语义
为了实现volatile语义,编译器在生成字节码的时候,会在指令序列中插入内存屏障来禁止特定类型的处理器排序。
常见的一些内存屏障以及内存语义可以参考:Java内存模型基础(JMM)_Edgar_HW的博客-CSDN博客Java内存模型https://blog.csdn.net/huangwei2014/article/details/128173421
针对volatile变量的不同操作,会插入不同的内存屏障,详情如下:
1. volatile变量的写操作
- 在每个写操作的前面加一个StoreStore屏障
- 在每个写操作的后面加一个StoreLoad屏障
一个StoreLoad屏障是一个全能型的屏障,同时具备LoadLoad和LoadStore以及StoreStore效果,同时效率也比较低
2. volatile变量的读操作
- 在每个读操作的后面加一个LoadLoad屏障
- 在每个读操作的后面加一个LoadStore屏障
上述的内存屏障策略是相对保守的,在实际执行的时候,只要不改变volatile的内存语义是可以生省略不必要的屏障的。