JUC學習--volatile關鍵字&內存可見性

學習記錄,若存在錯誤,請指出,謝謝!

首先,介紹一些內存可見性

內存可見性:當多個線程操作共享數據時,彼此不可見

爲什麼會導致這個情況?

在線程運行的過程中,JVM或者說是內存會爲每一個線程分配一個獨立的緩存用於提高效率。

舉個例子:現在有一個讀操作的線程和一個寫操作的線程,對主存中的一個共享變量進行操作
寫操作:線程先從主存中將共享變量讀到線程獨有的緩存中,然後對變量的值進行修改,最後再把修改後的變量的值寫回到主存中。
讀操作:讀取主存中共享變量的值
但是,

讀線程可能在寫線程把修改的變量的值寫回主存之前,就從主存中讀了變量的值,但是這個值是原先的值

public class TestVolatile {

    public static void main(String[] args){

        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(2000);
        }catch (InterruptedException e){
        }

        flag = true;
        System.out.println("flag = " + flag);
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

控制檯打印的結果:


這就導致了一個問題,寫線程已經把flag的值修改成了true,但是讀線程(也就是代碼中的main線程)並沒有輸出“-------”。

於是,我做了以下的修改

public class TestVolatile {

    public static void main(String[] args){

        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo).start();

        while(true){
            synchronized (threadDemo){
                if(threadDemo.isFlag()){
                    System.out.println("--------");
                    break;
                }
            }
        }
    }

}

在main線程中加上了synchronized關鍵字。於是


但是,使用了synchronize關鍵字之後,會導致程序的效率非常的低下。假設程序中有多個線程,每次訪問synchronized()這行代碼的時候,總是要判斷是否有別的線程佔有鎖,如果有,當前的線程就只能阻塞,直到CPU下次空閒的時候纔可能執行。

爲了保證程序的效率,就不能夠加鎖,但是又要解決內存可見性的問題,就要提到volatile關鍵字了。
volatile關鍵字:當多個線程對共享數據進行操作時,可以保證該共享數據是內存可見的。
原因是:volatile使用了計算機底層的內存柵欄,可以將線程獨立緩存中的值實時更新到主存中去,我們可以理解爲,直接對主存進行操作。

當然,使用了volatile關鍵字也會對系統的性能有一點損耗,因爲每進行一次操作,主存中的內容也會相應改變,但是效率比加鎖還是要高得多的。

private volatile boolean flag = false;

將共享變量flag用volatile關鍵字修飾。


但是,volatile並不能直接替代synchronized關鍵字,因爲相較於synchronized而言,volatile只是一種較爲輕量級的同步策略

注意:
volatile不具備“互斥性”;

volatile不能保證“原子性”;

若要滿足“互斥性”和“原子性”,則不能使用volatile



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