Volatile
明确三个定义:
-
原子性:要么全部执行且执行过程中不被其它因素干扰,要么就都不执行。
-
可见性:在jvm底层内存中,存在一个高速缓冲区,一个变量的创建,并不是直接存储到内存 中的,而是先存储到高速缓冲中,一个变量的读区,也不是直接从内存中读取,每一个线程都有自己的缓存,会先从缓存中读取,所以可见性就是一个变量的修改,其他线程能感知到这个变量值得变化从而区主存中读取,而不是直接在缓存中。
当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。 -
有序性:处理器为了提高运行速度可能会指令重新排序,但是会保证执行结果不变。
就是通过指令依赖性,
java内存模型中有先天的有序性也就是happens-before(先行发生原则) -
程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
-
锁定规则:一个unLock操作先行发生于后面对同一个锁的lock操作
-
volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
-
传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
一个共享变量添加了volatile关键字的意思就是保证了这个变量的可见性和禁止进行指令重排序。不一定保证原子性。
- 添加了volatile关键字会强制把修改过的值立即写入内存中,
- 当线程2修改的时候会导致线程1中的缓存变量stop的缓存行为失效。
volatile的原理和实现机制
前面讲述了源于volatile关键字的一些使用,下面我们来探讨一下volatile到底如何保证可见性和禁止指令重排序的。
下面这段话摘自《深入理解Java虚拟机》:
“观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”
lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2)它会强制将对缓存的修改操作立即写入主存;
3)如果是写操作,它会导致其他CPU中对应的缓存行无效。