JAVA内存从逻辑上可划分主内存与工作内存,这类划分不同于JVM中堆、线程栈及PC计数器等这类划分,如果非要等同,可以认为主内存指的是堆,工作内存指的是线程栈。工作线程使用主内存中变量采用的是创建变量副本及回写主存的方式,经历的步骤有:
1. read, 读取主内存变量值
2. load 加载至工作内存
3. use 在工作内存使用变量副本
4. assign 对变量重新赋值
5. store 保存变量值
6. write 更新主内存中变量值
以上每个步骤属于原子交易。
volatile关键词修饰的变量,能做到一个工作线程对变量的修改能在其它工作线程立即可见,如何做到这点的呢?
1. 主要在上面步骤3后面多加了read和load操作,也就是工作线程每次正要使用变量时重新从主内存快速读取一次(相当于刷新工作内存变量值)
2. 主要在上面步骤5后面多加了assign和store操作,保证了每次回显到主内存中的是最新变量值。
但由于整个流程并非一个原子性交易,所以不能完全保证线程安全。
可以从下面的例子体现中非线程安全:
public class Voliatie {
static volatile int i = 0;
public static void main(String[] args) {
for(int m =0; m<2000; m++) {
new Thread(){
public void run(){
for(int n=0; n<100;n++)
i++;
System.out.println(i);
}
}.start();
}
}
}
上面 i 的结果值不一定是200000,每次运行结果都可能不一样,这就是因为该交易非原子性交易带来的结果。