java线程可见性问题

java多线程可见性问题
flag先true后false导致不可见性,而且加sout和sleep会恢复,先false后true也不会发生可见性问题
public class VisibilityDemo01 {
public static void main(String[] args) {
    MyThread01 t = new MyThread01();
    t.start();
    while (true){
        if (t.isFlag()){
            System.out.println("entry");
        }
    }                         //flag先truefalse导致不可见性,而且加sout和sleep会恢复
                                //先falsetrue不会
}

}

class MyThread01 extends Thread {
public boolean flag = false;

public void run() {
    try {
        sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    flag = true;
    System.out.println(flag);
}

public boolean isFlag() {
    return flag;
}

}
//这个不会发生可见性问题

flag先false后true运行正常
刚开始我以为不会读取最新值,但现在这个结果又会读取最新值
为什么会出现flag先true后false导致不可见性,而且加sout和sleep会恢复,先false后true也不会发生可见性问题

这是因为在Java中,多线程之间的变量共享需要遵循一些规则来确保可见性。当一个线程修改变量时,其它线程可能并不能立即看到这个修改。在第一种情况中,主线程在子线程执行完之前就读取了变量的值,而子线程修改了变量之后主线程并不能立即看到这个修改,因此导致了不可见性问题。在第二种情况中,子线程在主线程读取变量之前就已经修改了变量,因此主线程能够看到这个修改。

在第一种情况中,加入sout和sleep的作用是在修改变量之后让主线程有时间读取到修改后的值,因此可见性问题得到了解决。

具体来说,解决方法有:

  • 使用volatile关键字修饰变量,这个关键字可以禁止指令重排和缓存,保证可见性.

  • 使用synchronized关键字修饰变量或方法,这个关键字可以禁止多线程并发访问,保证可见性.

  • 使用Lock锁,这个锁可以禁止多线程并发访问,保证可见性.

  • 使用Atomic类,这个类提供了CAS算法,保证可见性.