家乡的落日 2023-07-15 09:26 采纳率: 0%
浏览 11

Java多线程修改变量的可见性问题

运行以下Java代码:

public class Testjava6 {
private static boolean flag = false;
    static int i =0;
    public static void main(String[] args) {
       new Thread(() -> {
           try {
               Thread.sleep(1);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("线程1  修改了flag  为  true");
           flag = true;
        }).start();

        while (!flag){
            i++;
        }
        System.out.println("循环了 "+i+"次");
        System.out.println(flag);
    }
}


运行结果:

img

当把线程休眠时间设置为10毫秒


public class Testjava6 {
private static boolean flag = false;
    static int i =0;
    public static void main(String[] args) {


       new Thread(() -> {
           try {
               Thread.sleep(10);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("线程1  修改了flag  为  true");
           flag = true;
        }).start();

        while (!flag){
            i++;
        }
        System.out.println("循环了 "+i+"次");
        System.out.println(flag);
    }
}



运行结果 : 出现了死循环

img

请解释为什么会出现死循环
可以从变量的内存可见性,JIT及时编译器等方向进行分析

  • 写回答

2条回答 默认 最新

  • 藏柏 2023-07-19 15:38
    关注

    在第一个例子中,将线程休眠时间设置为1毫秒,线程有足够的时间去修改 flag 变量的值。因此,主线程最终能够检测到 flag 变为 true,并跳出循环。

    然而,在第二个例子中,将线程休眠时间增加到10毫秒。这可能导致了一种情况,即主线程在检测 flag 变量的值时,由于指令重排或优化等原因,可能不会重新从主内存中读取 flag 变量的最新值。相反,它可能仅仅在线程的工作内存中进行读取,而该工作内存中的值仍然是 false。因此,主线程将陷入无限循环,因为它无法检测到 flag 变为 true

    这是因为在多线程环境中,由于缓存和指令重排等原因,可能存在线程之间的数据不一致性。为了解决这个问题,可以使用同步机制,如 volatile 关键字或使用 synchronized 块,来确保变量的内存可见性和线程间的同步。

    在这个例子中,可以将 flag 变量声明为 volatile,这样就能确保每次读取 flag 变量时,都从主内存中获取最新的值。修改代码如下:

    public class Testjava6 {
        private static volatile boolean flag = false;
        static int i = 0;
    
        public static void main(String[] args) {
            new Thread(() -> {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程1  修改了flag  为  true");
                flag = true;
            }).start();
    
            while (!flag) {
                i++;
            }
            System.out.println("循环了 " + i + "次");
            System.out.println(flag);
        }
    }
    

    通过将 flag 声明为 volatile,可以确保变量的内存可见性,从而避免出现死循环的情况。

    评论

报告相同问题?

问题事件

  • 创建了问题 7月15日

悬赏问题

  • ¥15 Macbookpro 连接热点正常上网,连接不了Wi-Fi。
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题
  • ¥15 目标检测项目无法读取视频
  • ¥15 GEO datasets中基因芯片数据仅仅提供了normalized signal如何进行差异分析