Search code examples
javathread-safetyvolatile

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’

In the first sample, a typical sample of using 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======");
        }
    }
}

After started, the main thread won't find the change of flag unless using volatile

However, in the sample, unexpectedly, thread2 got the change of flag, why this happen?

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();
}

And After a try, I find if I remove the code

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

it will run as I thought, thread2 can't get the change.

Thanks for your answer, QwQ


Solution

  • May Be, in the second case, the io statement refresh the buffer zone of Thread

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

    if I use an io statement(Sout), it will work successfully. results of using io

    In this way, I keep finding reasons in println And I find the true reason

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

    synchronized caused the switch of thread

    and with the switch, the buffer zone of the thread was clear,

    so thread2 read a new value