这个关键字平时用的比较少,但是在面试的时候经常被问到,解释不清楚又比较尴尬,所以今天来聊一聊,java内存模型中所有的变量都是存放在内存中的,线程有自己的工作内存(类似于高速缓存),线程对变量的操作都是在工作内存中进行,不同的线程不能访问其他的线程的工作内存,画个图来表示下:
也就是说内存中的一个变量,每个线程类似于保存了该变量的一个副本,线程对该变量的修改会先保存到工作内存中,然后再同步到内存中,这样,当多个线程访问该变量的时候,就可能出现问题,看如下代码(假设a和b的初始值都为0):
//线程1
a = 5;
//线程2
b = a;
假设线程1在CPU1中执行,线程1的工作内存中a的值已经变为10了,但是还没来得及同步修改到内存,这时,线程2的工作内存中a的值还是0(由于线程1修改了工作内存中的a的值,没有同步到内存,那么这时其他线程的工作内存中a的值也就不会改变),所以b的值也是0,这跟我们期望的b的值是a的值不符,这就是问题所在,那么用volatile修饰的变量是什么情况呢,使用volatile关键字会强制将修改的值立即写入内存,a的值在线程1中被修改,会立刻写入到内存,并且使其他线程(这里是线程2)的工作内存中的a的值失效,那么线程2就会立刻去内存中读取最新的值了,使用volatile关键字还有一个好处就是防止指令重排序,JVM在解释代码的时候有可能在不影响程序正确性的情况下把顺序打乱,如果用volatile关键字,这个问题就不存在,但是使用volatile关键字不能保证原子性,比如a++这种涉及到三个操作,读a的值,然后进行+1,再保存,volatile只能保证可见性,也就是当修改的时候,才会立刻同步到内存,但是如果读操作,没有同步的话,一样会出问题,无法保证原子性。
总结下:
使用volatile关键字可以保证可见性,防止指令重排序,但是无法保证原子性。