Volatile的作用
- 内存可见性
- 防止指令重排
Volatile是如何保证内存可见性的?
CPU多级缓存
CPU的运行速度非常快,而对磁盘的读写IO速度却很慢,为了解决这个问题,有了内存的诞生;
而CPU的速度与内存的读写速度之比仍然有着
100 : 1
的差距,为了解决这个问题,CPU又在内存与CPU之间建立了多级别缓存:寄存器、L1、L2、L3三级缓存。
CPU三级缓存.png
CPU缓存一个最小单位是64Byte:经过实践得出,缓存64Byte是一个较为合适的单位大小,不会因为缓存过大,而使得读取速度降低,也不会因为缓存过少,而多次去读取数据。
当核心1
与核心2
在操作同一缓存行中的不同元素时,即使是操作的不同元素不会相互造成影响,但是,同一缓存行数据若被修改,则会通过缓存一致性协议来使其他CPU与核心中的缓存失效,从而重新去内存中读取数据,造成程序速度变慢。
- 奇技淫巧:在这种情况下,通过“补齐”一块
64Byte
大小的空间,来使得缓存不会因为一致性问题而重复更新。 - 实际应用场景:
disruptor
并发框架JDK8
可以用注解@Sun.misc.Contended
实现两个对象或者变量绝对不在同一块缓存行内。
CPU为什么会指令重排?
我们的程序运行时,会被编译器转化成一条一条CPU能够执行的语句,例如下面的程序:
int a = 1;
int b = 1;
a = a + b;
a++;
简单地观察即可发现,第4行与第5行的语句交换顺序执行并不会发生最终结果的不一致。
这为CPU指令重排提供了重排的可行性!
而根本原因是:CPU运行速度与内存读取速度不匹配,第4行的语句会让CPU到内存中寻找b的值,从而使CPU空闲时间过多,而考虑到效率问题,CPU就在这一段读取内存的空闲时间内,先执行了下一条语句,提高程序运行效率。
不允许重排序情况:
happen-before
:六项规则as if serial
:单线程执行结果不能被改变DCL(Double Check Lock)单例模式
:防止对象未创建完成,就已经被另一个线程返回了- ……
volatile 内存屏障
的hot spot
实现:
lock
cpu总线,使CPU缓存中的数据失效,使得其他CPU暂时停止工作达到防止指令重排序。