volatile关键字的作用:
1、保证修饰的属性具有可见性
2、可以禁止指令重排序,从而实现了有序性
首先来解释下可见性:
volatile修饰的变量对所有线程都是可见的,是指当一个线程修改了这个变量的值,新值对于其他线程来说可以立即得知。而普通变量做不到这一点,普通变量的值在线程间传递均需要通过主内存来完成,例如,线程A修改一个普通变量的值,然后向主内存进行回写,另一条线程B在线程A回写完成之后,再从主内存中进行读取操作,新变量的值才会对线程B可见。
有序性:
CPU为了提高执行效率,在执行机器指令时可能会发生乱序的情况。在单核CPU中代码顺序与机器指令顺序的不一致不会导致结果变化。但是在多核CPU中则会出现数据不安全的情况。主要是因为多个CPU在并发情况下处理数据时,编译器对机器指令进行了顺序调优,一个线程获取的值可能为另一个线程乱序执行得出的值。(一句代码可能会编译出多句机器指令)
使用volatile可以禁止指令重排序。转换成机器指令的话,会发现有一个Lock前缀,就是对它的读写操作加了“内存屏障”,对这个变量的所有操作都执行完后,再同步到内存中,期间不允许其他的指令执行,所以说是形成了内存屏障。
性能问题
volatile的同步机制确实优于锁,(synchronized关键字或是JUC包中的锁)但是由于虚拟机进行了许多优化升级,我们也并不能认为volatile比锁快多少。
首先,volatile修饰的变量进行读操作与普通变量几乎没什么差别,但是写操作相对慢一些,因为它需要在本地代码中插入很多内存屏障来保证指令不会发生乱序执行,但是开销总是比锁要小。对于synchronized和volatile的选择,一般看volatile的语义能否满足使用场景的需求。