什么是Volatie关键字?
Volatile是类似于static的关键字(从使用位置上来说),但是只能使用在变量的前面
Volatile的两个语义
1.可见性和一致性
当一个变量声明为volatile之后,他将具备两种特性,第一是保证此变量对所有线程的可见性,这里的可见性是指当一条线程修改了这个变量的值,新值对其他线程来说是可以立即得知的.而普通变量不能做到这一点.普通变量的值在线程间传递均需要通过主内存来完成.
由于volatile变量的可见性,经常会被开发人员误解,认为"volatile既然是可以立即得知的,那么volatile变量在各个线程中是一致的,所以基于volatile变量的运算在多线程环境下是安全的".volatile变量在各个线程的工作内存中不存在一致性问题(在各个线程中,volatile变量也可以存在不一致的情况,但是由于每次使用前都要先刷新,执行引擎看不到不一致的情况,因此可以认为不存在一致性问题),但是在Java里面的运算并非原子操作,导致volatile变量的运算在并发情况下一样时不安全的.举个栗子:
结果:
结论:可以看到,结果并不是我们期望的200000,为什么呢?问题就出在count++上面!看下图:
看这个图只需要明白一点,虽然在Java代码中count++看似一句,但是到字节码文件中就是四个指令了,并不能保
证数据的一致性,意思是说volatile能保证在执行getstatic指令时线程拿到准确的数据,但是执行到iconst_1或者
iadd时可能已经有其他线程把值已经放回栈顶,这时候当前线程拿到的值就是过期值,所以会出现数据的丢失.
2.禁止指令重排序
指令重排序是JVM优化策略之一,从硬件架构上将,指令重排序是指CPU采用允许将多条指令不按程序规定的顺序分开发送给各响应电路单元处理,两句毫不相干的代码(不满足先行发生原则)在Java代码中有顺序,但是在JVM中的执行顺序可能不是按照Java代码的顺序来执行.而volatile能禁止指令重排序,说那么多,上代码就知道了!!
这里如果不加volatile,那么initialized = true,这段代码可能会由于指令重排序得优化,导致配置信息还没有配置完成,线程B就
过
来拿着配置信息做事了.而volatile关键字能避免这类情况发生.
总结:
在某些情况下,volatile的同步机制性能确实要由于锁(使用synchronized关键字或者java.util.concurrent包里面的锁),但是由于
虚拟机对锁进行了许多消除和优化,很难量化地认为volatile就会比synchronized快多少.如果让volatile自己与自己比较,那可以确定
一个原则:volatile变量读操作的性能消耗与普通变量几乎没有什么差别,但是写操作则可能会慢一些,因为它需要在本地费吗中插入许多内存屏障指令来保证处理器不发生乱序执行.不过即便如此,大多数场景下volatile的总开销仍然要比锁低,我么在volatile在锁之中选择的唯一依据仅仅是volatile的语义能否满足使用场景的需求
嗯~~本文主要借鉴了<深入理解Java虚拟机>~~有什么不对的 欢迎来打我呀~~~