Java(11)中线程间共享变量的问题

Problem about shared variable between threads in Java(11)

maybe what I hope to express isn't so clearly, the first case is a sample about when and how to use volatile, And to make the program run successfully, We need to add the volatile.

the second is in the hope to express that, even without the volatile, the program sitll run successfully. And I hope to know why this will happen without ‘volatile’

在第一个示例中,使用 volatile 的典型示例

public static int num=1;

public static class MyThread extends Thread {
    // flag
    private boolean flag = false ;
    public boolean isFlag() { return flag;}
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) { e.printStackTrace();
        }
// change flag to true
        this.flag = true ;
        System.out.println("flag=" + flag);
        this.flag=true;
    }
}
// main
static void testWithOutVolatile(){
    MyThread t=new MyThread();
    t.start();
    while(true) {
        boolean is=t.flag;
        if (is) {
            System.out.println("run======");
        }
    }
}

主线程启动后,除非使用volatile才能发现flag的变化

然而,在示例中,意外地,线程2得到了标志的变化,为什么会这样?

static int amb=0;
static void testSimple(){
    Thread t1=new Thread(()->{
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        amb++;
    });
    Thread t2=new Thread(()->{while(true) {
        if (amb == 0) {
            System.out.println("no");
        }
        if (amb != 0) {
            System.out.println("SUc");
            break;
        }
    }});
    t2.start();
    t1.start();
}

经过尝试,我发现如果我删除代码

if (amb == 0) {
            System.out.println("no");
        }

会运行和我想的一样,thread2拿不到零钱

感谢您的解答,QwQ

可能是, 第二种情况,io语句刷新Thread

的缓冲区
Thread t2=new Thread(()->{while(true) {
        System.out.println("no");
        if (amb != 0) {
            System.out.println("SUc");
            break;
        }
    }});

如果我使用 io 语句 (Sout),它将成功运行。

就这样一直在println里找原因 我找到了真正的原因

 public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

同步导致线程切换

有了开关,线程的缓冲区就清晰了,

所以线程 2 读取了一个新值