目录
理解:
一般使用时的目的,是为了防止指令重新排列;作用,是保持全局可见性;使用范围上,只用于变量;
1 .禁止指令重排
指令重排序是JVM为了优化指令、提高程序运行效率,在不影响单线程程序执行结果的前提下,尽可能地提高并行度。指令重排序包括编译器重排序和运行时重排序。
latile变量禁止指令重排序。针对volatile修饰的变量,在读写操作指令前后会插入内存屏障,指令重排序时不能把后面的指令重排序到内存屏
示例说明:
double r = 2.1; //(1)
double pi = 3.14;//(2)
double area = pi*r*r;//(3)
虽然代码语句的定义顺序为1->2->3,但是计算顺序1->2->3与2->1->3对结果并无影响,所以编译时和运行时可以根据需要对1、2语句进行重排序。
volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错
2.保证内存可见性(即全局性变量)
可见性是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果,另一个线程马上就能看到。
实现原理
当对非volatile变量进行读写的时候,每个线程先从主内存拷贝变量到CPU缓存中,如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的CPU cache中。
volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,保证了每次读写变量都从主内存中读,跳过CPU cache这一步。当一个线程修改了这个变量的值,新值对于其他线程是立即得知的。
3.只能用来修饰变量
#############################################################################
volatile底层实现原理
volatile变量自身具有下列特性:
可见性。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。
其实现原理为:
1,通过插入内存屏障指令(lock屏障指令)禁止编译器和CPU对程序进行重排序。
2,当对声明了volatile的变量进行写操作时,JVM就会向处理器发送一条Lock前缀的指令,这条Lock前缀指令产生如下两个作用:
1)Lock前缀指令会引起处理器缓存回写到系统内存,并使用缓存一致性机制来确保回写的原子性。
2)一个处理器的缓存回写到系统内存会导致其他处理器的缓存无效。处理器使用MESI控制协议去维护内部缓存和其他处理器缓存的一致性。处理器能嗅探其他处理器访问系统内存和它们的内部缓存。处理器使用嗅探技术保证它的内部缓存、系统内存和其他处理器的缓存的数据在总线上保持一致。例如,在Pentium和P6 family处理器中,如果通过嗅探一个处理器来检测其他处理器打算写内存地址,而这个地址当前处于共享状态,那么正在嗅探的处理器将使它的缓存行无效,在下次访问相同内存地址时,强制执行缓存行填充。
3.不保证原子性
volatile只有写操作是原子性的,也就是数据操作完成后会立刻刷新到主内存中。但是被volatile修饰的变量在读的时候可能会被多个线程读。也就是说int i = 1;i++;
A线程读 i = 1同时B线程也读了i = 1,然后自增完成刷新入主内存。i的值是2。
所以如果该变量是volatile修饰的,那可以完全保证此时取到的是最新信息。但在入栈和自增计算执行过程中,该变量有可能正在被其他线程修改,最后计算出来的结果照样存在问题,因此volatile并不能保证非原子操作的原子性,仅在单次读或者单次写这样的原子操作中,volatile能够实现线程安全。
解决原子性的方法
1、通过synchronized关键字/lock锁等。
2、通过使用AtomicXX,不加锁,采用CAS(compareAndSet)解决。其本质是使用UnSafe本地方法(CPU原语)。
3、使用LongAdder:最快(在线程多的情况下,使用分段锁)
用法示例
主要注意,当启用一个线程时候,每个线程都会把共享变量复制一份到工作内存中,如下图所示
volatile的用法示例_会飞的狼阿海的博客-CSDN博客_volatile用法和案例
相关文章: