要明白什么是内存可见性,我们首先来看一段代码
- public class demo1 {
- public static int isQuit = 0;
-
- public static void main(String[] args) {
- Thread thread1 = new Thread(()->{
- while (isQuit == 0){
-
- }
- System.out.println("t1线程结束");
- });
- thread1.start();
-
- Thread thread2 = new Thread(()->{
- Scanner scanner = new Scanner(System.in);
- isQuit = scanner.nextInt();
- System.out.println("isQuit已被修改");
- });
- thread2.start();
- }
- }
运行结果如下

打开jconsole,查看thread1状态,发现thread1还在运行状态,也就是说thread1中的while循环还一直在继续

为什么会这样呢?
在计算机中,CPU在读取寄存器时比读取内存时快很多,这时编译器会对代码进行自动优化
在上述代码中,由于while循环中没有代码,线程1不断地读取isQuit的值进行判断,操作过于频繁
因此,编译器在第一次读取isQuit的值后,便将其存放在寄存器中,后续不再读取
导致我们在线程2里对isQuit 的值进行了修改,线程1也不能察觉
由此便产生了内存可见性问题
要解决内存可见性问题,我们首先想到的是使用Java中的关键字volatile
在变量前加上关键字volatile修饰,变量便不会再被编译器优化,进而就不会产生内存可见性问题
public volatile static int isQuit = 0;
完整代码如下
- import java.util.Scanner;
-
- public class demo2 {
- public volatile static int isQuit = 0;
-
- public static void main(String[] args) {
- Thread thread1 = new Thread(()->{
- while (isQuit == 0){
-
- }
- System.out.println("t1线程结束");
- });
- thread1.start();
-
- Thread thread2 = new Thread(()->{
- Scanner scanner = new Scanner(System.in);
- isQuit = scanner.nextInt();
- System.out.println("isQuit已被修改");
- });
- thread2.start();
- }
- }
最终运行结果

可见,内存可见性问题可用volatile关键字来解决
之所以产生内存可见性问题,是由于读取操作太过于频繁。只要我们降低读取的频率,同样也可以解决内存可见性问题
如在线程1中的while循环中加上sleep操作
- import java.util.Scanner;
-
- public class demo3 {
- public static int isQuit = 0;
-
- public static void main(String[] args) {
- Thread thread1 = new Thread(()->{
- while (isQuit == 0){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- System.out.println("t1线程结束");
- });
- thread1.start();
-
- Thread thread2 = new Thread(()->{
- Scanner scanner = new Scanner(System.in);
- isQuit = scanner.nextInt();
- System.out.println("isQuit已被修改");
- });
- thread2.start();
- }
- }
运行结果
