volatile關鍵字理解

先看代碼

public class Test {

    private static int init_value = 0;

    public static void main(String[] args) {

        new Thread(() -> {
            int a = init_value;
            while (a < 500) {
                if (a != init_value) {
                    System.out.printf("the value is update to [%d]\n" , init_value);
                    a = init_value;
                }
            }
        }, "read").start();

        new Thread(() -> {
            int a = init_value;
            while (a < 500) {
                System.out.printf("the value is change to [%d]\n", a++);
                init_value = a;
            }
        }, "update").start();
    }
}

執行結果:線程update會一直執行,線程read不會執行,執行狀況一直如此。java

執行結果

volatile關鍵詞如何保證可見性

緣由分析:線程read,沒法感知init_value的變化,由於線程read中讀到的init_value值一直都是緩存中的值,沒有讀到主內存的值,因此init_value的值永遠是0.緩存

緩存的效率是比主存的速度快的,加入緩存的目的是爲了提升訪問速度,可是加入緩存後也出現了數據一致性的問題,尤爲是在多線程的環境下。多線程

執行結果

程序處理a++的具體流程:
一、讀取主存中的 a 到CPU Cache中。線程

二、對a進行加1操做。code

三、將結果寫入到CPU Cache中。blog

四、將數據刷新到主存中。排序

在加上valotile以後在read線程中就能看到init_value的變化。內存

private volatile static int init_value = 0;資源

可見volatile的做用之一就是保證變量的可見性,它能讓數據直接同步到主存中去,讓緩存中的數據失效。同步

當一個變量被volatile關鍵詞修飾時,對於共享資源的讀操做會直接在主存中執行,固然也會緩存到工做內存,當其餘線程對共享資源進行修改,會致使當前線程在工做內存中的共享資源失效,因此必須從主存中再次獲取,對於共享資源的寫操做固然是要先修改工做內存,修改結束後再刷新到主內存。所以volatile關鍵字沒法保證原子性,只能保證可見性。

volatile保證有序性

volatile關鍵詞直接禁止JVM對volatile關鍵字修飾的指令進行從新排序。但對於先後無依賴關係的指令則能夠隨意排序。

int x = 0;
int y = 1;
volatile int z = 20;
x++;
y--;

volatile int z = 20;以前,x和y的執行順序並不關心,只要能保證到執行z = 20時,x=0 y=1就好了。
至於後面的x++ y--哪條指令先執行也不用關心。

private volatile boolean initialized = false;
private Context context;

public Context load() {
     if (initialized) {
         context = loadContext();
         initialized = true; // 禁止指令重排
     }
     return context;
}

initialized被volatile修飾,這就意味着,當initialized=true時,loadContext()方法是必定執行完成的。

相關文章
相關標籤/搜索