volatile
1、参考资料
https://www.cnblogs.com/zhengbin/p/5654805.html
2、volatile特点
- 可见性
- 禁止指令重排(有序性)
- 不能保证原子性
3、可见性
当对非 volatile 变量进行读写的时候,每个线程先将变量从线程内存拷贝到CPU缓存,再将cpu缓存写入主存(但写入时间不定)。
若变量被 volatile修饰,则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。
4、禁止指令重排序优化(有序性)
指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理。
//x、y为非volatile变量
//flag为volatile变量
x = 2; //语句1
y = 0; //语句2
flag = true; //语句3
x = 4; //语句4
y = -1; //语句5
由于flag变量为volatile变量,那么在进行指令重排序的过程的时候,不会将语句3放到语句1、语句2前面,也不会讲语句3放到语句4、语句5后面。但是要注意语句1和语句2的顺序、语句4和语句5的顺序是不作任何保证的。
并且volatile关键字能保证,执行到语句3时,语句1和语句2必定是执行完毕了的,且语句1和语句2的执行结果对语句3、语句4、语句5是可见的。
5、使用volatile保证long和double的操作为原子操作
java对long和double的赋值操作是非原子操作!!long和double占用的字节数都是8,也就是64bits。在32位操作系统上对64位的数据的读写要分两步完成,每一步取32位数据。这样对double和long的赋值操作就会有问题:如果有两个线程同时写一个变量内存,一个进程写低32位,而另一个写高32位,这样将导致获取的64位数据是失效的数据。因此需要使用volatile关键字来防止此类现象。volatile本身不保证获取和设置操作的原子性,仅仅保持修改的可见性。但是java的内存模型保证声明为volatile的long和double变量的get和set操作是原子的。