关于在测试volatile关键字时碰到的一个问题

当时在学习volatile关键字,首先写了一段这样的代码:

public class TestVolatile {


    static boolean flag = false;

    public static void main(String[] args) {

        new Thread(()->{
            while (!flag){
            }
        },"t1").start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        flag = true;
    }
}

正常情况下,这段代码是不会因为由于主线程修改flag的值,t1线程就会停下来的。但是当我在t1的while循环里面加入了一行代码:System.out.println();即代码变成了下面的:

public class TestVolatile {


    static boolean flag = false;

    public static void main(String[] args) {

        new Thread(()->{
            while (!flag){
                System.out.println();
            }
        },"t1").start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        flag = true;
    }
}

奇怪的是,1秒后,t1线程居然停下来了,想不明白这是为什么,后来查阅资料后得出以下结论:

  • 在Java中,System.out.println() 操作会导致I/O操作,这可能会触发同步机制,强制将线程的本地缓存与主内存进行同步。这意味着,由于I/O操作,System.out.println() 可能会导致在这个操作执行期间,CPU将对 flag 的缓存刷新到主内存,确保了在新启动的线程中能够看到最新的 flag 值

但是需要注意的是:

  • 即使这种方式可能偶然地解决了可见性问题,这种做法仍然是不推荐的。因为依赖于 System.out.println() 或者其他非同步操作来解决并发问题是不可靠的,不同的JVM、操作系统或环境下可能表现不同。正确的做法是使用专门的并发控制手段(如 volatile、锁等)来确保可见性和线程安全,而不是依赖于不可靠的副作用。

你可能感兴趣的:(java,开发语言,并发编程,可见性,JMM,volatile)