一個Java線程間內存可見性實例的解讀

代碼來源

public class TestVolatile {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo).start();
        while (true) {
            if (threadDemo.isFlag()) {
                System.out.println("-------------------可見");
                break;
            }
        }
    }
}
class ThreadDemo implements Runnable {
    private volatile boolean  flag = false;
    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.print("flag = " + isFlag());
    }
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

直接運行這個代碼,將輸出 flag = true ,並進入死循環。

因此可以驗證主線程是無法獲得new Thread()線程中的flag變量的,flag在兩個線程間是不可見的。

但看完代碼,我對Thread.sleep(200)這部分代碼很疑惑,把它註釋掉,會導致以下輸出

-------------------可見
flag = true

flag加上volatile修飾可以讓它在線程間可見我知道,但爲什麼一個Thread.sleep(200);會導致線程間不可見規律的失靈?

==================================================================================

原來還是我對 線程間內存不可見問題 的本質認識不足,只是把它當做一個規律記住了。

這篇文章講的很好:談談Java中的volatile

看完這篇文章我知道了:

各個線程都會從主內存中複製一個變量的副本到自己的本地內存中進行操作,並在稍後將修改後的變量值同步到主內存。

 

對應現在這個實例來說:

Thread.sleep(200)會延緩new Thread()線程修改flag、同步到主內存的速度。進而使主線程從主內存中複製的是flag的舊值,並因線程間內存修改的不可見性,主線程會一直讀取自己空間中的flag,不會再更新。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章