volatile是如何保证可见性的呢?
在X86处理器下通过工具获取JIT编译生成的汇编指令来查看对volatile进行写操作时,CPU会做什么?
java代码:
instance = new Singleton(); // instance是volatile变量
转变成汇编代码
0x01a3de1d: movb $0×0,0×1104800(%esi);
0x01a3de24: lock addl $0×0,(%esp);
有volatile修饰的共享变量进行写操作的时候会多出第二行汇编代码,通过查IA-32架构软件开发者手册可知,Lock前缀的指令在多核处理器下会引发了两件事情:
1、将当前处理器缓存行的数据写回到系统内存
2、这个写回内存的操作会使在其它CPU里缓存了盖内存地址的数据无效
详细解释:
为了提高
处
理速度,
处
理器不直接和内存
进
行通信,而是先将系
统
内存的数据
读
到内部
缓
存(
L1
,
L2
或其他)后再
进
行操作,但操作完不知道何
时
会写到内存。如果
对
声明了
volatile
的变量
进
行写操作,
JVM
就会向
处
理器
发
送一条
Lock
前
缀
的指令,将
这
个
变
量所在
缓
存行的数据写回到系统
内存。但是,就算写回到内存,如果其他
处
理器
缓
存的
值还
是旧的,再
执
行
计
算操作就会有问题
。所以,在多
处
理器下,
为
了保
证
各个
处
理器的
缓
存是一致的,就会
实现缓
存一致性协议
,每个
处
理器通
过
嗅探在
总线
上
传
播的数据来
检查
自己
缓
存的
值
是不是
过
期了,当处理器
发现
自己
缓
存行
对应
的内存地址被修改,就会将当前
处
理器的
缓
存行
设
置成无效状态,当
处
理器
对这
个数据
进
行修改操作的
时
候,会重新从系
统
内存中把数据
读
到
处
理器
缓
存里。
参考资料:Java并发编程的艺术