1. 程式人生 > >最通俗易懂的volatile關鍵詞詳解

最通俗易懂的volatile關鍵詞詳解

一、volatile能保證可見性

在描述可見性之前,首先要講解一下Java的記憶體模型,Java記憶體模型規定了了所有變數都儲存在主存中,每條執行緒中還有自己的工作記憶體,執行緒的工作記憶體內儲存了執行緒所使用到的變數,這些變數是從主存中拷貝而來,不同執行緒的工作記憶體互相隔離,執行緒間的變數值傳遞都要通過主存;執行緒對變數的所有操作(讀取、賦值)都必須在工作記憶體中進行。 在這種記憶體模型下,很有可能產生髒讀現象。如在某個執行緒執行語句:i = 1; Java虛擬機器是這樣執行的:先把i讀進到工作記憶體中,然後對變數i所在的工作記憶體進行賦值操作,最後寫回到主存。 在這種機制下,很容易讓其他執行緒無法讀到最新的值,因為很有可能在某個執行緒做完賦值操作,但是還未做回寫操作就進入其他狀態暫時未往下執行了,這時候這個新值對於其他執行緒是不可見的。
 但是在使用volatile修飾變數後,會強制將修改的值立即寫回主存。

二、volatile不能保證原子性

考慮一個自增操作:i++,這個操作需要經歷四步:(1)讀取i變數到工作記憶體 (2)對變數做+1操作(3)將變數寫回主存。這三步在進行過程中,volatile並不能保證這三步會一起執行完或一條也不執行完,其他執行緒在這三步執行過程中也可以對i進行操作,所以無法保證原子性。

三、volatile能保證有序性

volatile可以禁止部分指令重排序,即能在一定程度上保證指令的有序性。何為指令重排序?先看一段程式碼
        //執行緒1
        int result = cacu();//語句1
        boolean ok = true;//語句2

        //執行緒2
        while (!ok){
            //sleep
        }
        use(result);//語句3
Java虛擬機器不會按順序執行這些語句編譯後的指令,可能會先執行語句2,再執行語句1,這樣的話可能會導致大問題,如果執行緒1先執行了語句2而未來得及執行語句1,執行緒2察覺到ok=true,則直接執行語句3,而這時result並未賦值。 但是在Java虛擬機器不會對互相有依賴關係的指令進行重排序,比如說 a = b + c; d = a / 2;這兩條語句,就不會被重排序。 但是如果對ok變數加上volatile關鍵字,那就不一樣了,volatile為修飾的變數提供了一層記憶體屏障,在位元組碼中是在store指令後會有lock add1指令,就代表 在volatile指令修飾變數的操作指令前的指令都會先於該指令執行,即語句1會先於語句2執行,在volatile指令修飾變數的操作指令後的指令都會後於該指令執行。即語句2後面的語句都會後於語句2執行。
因此volatile關鍵字可以保證有序性。