目录
volatile关键字可以保证内存的可见性
内存可见性问题
1、产生原因
计算机在运行是程序和代码,要经常访问数据,这些依赖的数据,往往会存储在内存中
cpu使用数据的时候,就会把这个内存中的数据,先读取出来,然后放到cpu的寄存器中,再参与运算,但cpu读取内存的时候是非常慢的。
为了解决上述问题,提高效率,此时编译器就可能对代码进行优化,把一些本来要读取内存的操作,优化成读取寄存器,减少读取内存的次数,也就可以提高整体程序的效率。但当对内存中的数据进行操作时,编译器并没有读取更新后的内存,而是继续读取编译器,就形成了没有更新成功的现象,这就是“内存可见性问题“。
例如:
import java.util.Scanner;
public class demo {
private static int isQuit=0;
public static void main(String[] args) {
Thread t1=new Thread(()->{
while (isQuit==0){
//一直循环
}
System.out.println("t1退出");
});
t1.start();
Thread t2=new Thread(()->{
System.out.println("请输入isQuit");
Scanner scanner=new Scanner(System.in);
isQuit=scanner.nextInt();
});
t2.start();
}
}
在循环中
1、通过load读取内存中的isQuit的值到寄存器
2、通过cmp指令比较寄存器的值是否为0,决定是否需要继续循环
由于这个循环的速度飞快,短时间内会产生大量的循环,也就是大量的load和cmp操作
此时,编译器就发现了,多次load的结果都是一样的,非常浪费时间。所以编译器就进行了优化,只让第一次的循环的时候读取了内存,后续直接在寄存器上取值,无法感受到内存的变化。
当t2线程修改isQuit为非0的值的时候,t1线程也并没有结束,此处就发生了”内存可见性问题”。
2、解决方法
volatile就是解决方案
通过volatile关键字,可以告诉编译器不要优化。
只需要给isQuit关键字加上volatile关键字修饰
private volatile static int isQuit=0;
import java.util.Scanner;
public class demo {
private volatile static int isQuit=0;
public static void main(String[] args) {
Thread t1=new Thread(()->{
while (isQuit==0){
//一直循环
}
System.out.println("t1退出");
});
t1.start();
Thread t2=new Thread(()->{
System.out.println("请输入isQuit");
Scanner scanner=new Scanner(System.in);
isQuit=scanner.nextInt();
});
t2.start();
}
}
此时将isQuit改为非0的值时,while循环就会结束。