volatile的作用和缺陷

volatile是一个修饰符,用于多线程环境下变量的共享,正式一点说就是满足内存变量的“可见性”。

volatile修饰的变量有3个特点:

  1. 保证可见性
  2. 不保证原子性
  3. 禁止指令重排序

可见性:内存有主内存(内存条,供整个系统使用的内存)和线程工作内存(线程自己独占的内存),一般的变量在多线程读取的时候都是各自copy一份到自己的工作内存,互不想干。变量加上了volatile修饰符就相当于多了一个广播机制,某一个线程改了这个值,就会同步回主内存并且通知到其他线程。

不保证原子性:cpu的执行效率和主内存读写效率不是一个量级,多线程环境下容易出现线程A还没把变量同步回主内存并且通知其他线程的时候,其他线程已经从主内存取值并执行了,最终因为丢失更新导致数据不对。多线程环境下对变量做处理的时候我们一般会考虑使用JUC下的AtomicXXX类替代。

禁止指令重排序:指令重排是编译器为了优化字节码的执行效率,在编译的时候修改了代码的执行次序。只要有的变量的更新与其他变量没有依赖关系,就有可能被提到靠前的执行位置。多线程环境下,指令重排可能导致位置的代码执行逻辑问题。

例如: 初始变量int a=0; boolean f=false;
线程A执行了方法:a+=1; ... f=true;
线程B执行了方法:while(f){a+=5;}return a;
A的方法发生了指令重排,可能会让f=true先执行。导致a还没+1就被线程B抢占执行了while,最终a=5;而我们的预期是a应该为6;

所以,解决多线程问题我们可以用volatile,JUC包,或者synchronize,前2者效率要高,因为synchronize使代码执行完全变成了单线程。

你可能感兴趣的:(volatile的作用和缺陷)