volatile与JMM
2大特点
可见性
有序性-->有时需要禁止重排
内存语义
当写一个volatile变量时,JMM会把该线程的本地内存中的共享变量值 立即刷新回主内存中
当读一个volatile变量时,JMM会把该线程对应的本地内存设置为无效,重新回到主内存中读取最新共享变量的值
所以volatile的写内存语义是直接刷新到主内存,读的没存语义是直接从主内存中读取
保证可见性和有序性
内存屏障 Memory Barrier
写屏障(Store Memory Barrier):告诉处理器在写屏障之前将所有存储在缓存(store buffers)中的数据同步到主内存。就是说 当看到Store屏障指令,就必须把该指令之前所有写入指令执行完毕才能继续往下执行
读屏障(Load Memory Barrier):处理器在读屏障之后的读操作,都在读屏障之后执行。在Load屏障指令之后能够保证后面的读取指令一定能读到最新的数据
对于一个volatile变量的写,先行发生于这个volatile变量的读,也叫 写后读。
保证可见性:保证不同线程对 某个变量完成操作后结果及时可见,即该共享变量一旦改变所有线程立即可见
细分4种屏障
loadload:读读屏障
storeload:写读屏障
loadstore:读写屏障
loadload:写写屏障
volatile变量不适合参与到依赖当前值的运算
原因:JVM的字节码,i++分成三步,间隙期不同步非原子操作
重排序
存在数据依赖关系,禁止重排序===>重排序发生,会导致程序运行结果不同。如
- 写后读
- 写后写
- 读后写
数据依赖性:若两个操作访问统一变量,且这两个操作中有一个为写的操作,此时量操作间就存在数据依赖性
指令禁重排
第一 为volatile 读,第二 不论
第二 为volatile 写,第一不论
第一 为volatile 写,第二 为volatile 读,
这几种皆不能重排序
volatile使用场景
单一赋值(不可用于 复合运算 i++类)
状态标志
开销低的读写策略
DCL双端锁
- 本文标签: Java
- 本文链接: http://119.91.109.247:8443//article/83
- 版权声明: 本文由张亚东原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权