线程间可见性: 一个线程变更了 先存在cpu三级缓存 中 再刷到内存 另一个线程读自己的三级缓存或内存 导致数据不一致
volatile
1可使cpu三级缓存失效 线程变更刷内存 另一个线程只读内存
2禁止指令重排序
synchronized = volatile+ 线程间互斥(同一时刻只能有一个进行写操作)
在程序运行时,为了提高执行性能,编译器和处理器会对指令进行重排序,JMM为了保证在不同的编译器和CPU上有相同的结果,通过插入特定类型的内存屏障来禁止特定类型的编译器重排序和处理器重排序,插入一条内存屏障会告诉编译器和CPU:不管什么指令都不能和这条Memory Barrier指令重排序。
代码块
class Singleton {
private volatile static Singleton instance;
private int a;
private int b;
private int c;
public static Singleton getInstance() {
if (instance == null) {
syschronized(Singleton.class) {
if (instance == null) {
a = 1; // 1
b = 2; // 2
instance = new Singleton(); // 3
c = a + b; // 4
}
}
}
return instance;
}
}
1、如果变量instance没有volatile修饰,语句1、2、3可以随意的进行重排序执行,即指令执行过程可能是3214或1324。
2、如果是volatile修饰的变量instance,会在语句3的前后各插入一个内存屏障。
通过观察volatile变量和普通变量所生成的汇编代码可以发现,操作volatile变量会多出一个lock前缀指令:
代码块
Java代码:
instance = new Singleton();
汇编代码:
0x01a3de1d: movb $0x0,0x1104800(%esi);
0x01a3de24: **lock** addl $0x0,(%esp);