1. 程式人生 > >執行緒中的關鍵字volatile的介紹

執行緒中的關鍵字volatile的介紹

volatile關鍵字修飾 變數:可以保證變數的可見性和防止程式指令重排序

想要理解volatile為什麼能確保可見性,就要先理解Java中的記憶體模型是什麼樣的。

Java記憶體模型規定了所有的變數都儲存在主記憶體中。每條執行緒中還有自己的工作記憶體,執行緒的工作記憶體中儲存了被該執行緒所使用到的變數(這些變數是從主記憶體中拷貝而來)。執行緒對變數的所有操作(讀取,賦值)都必須在工作記憶體中進行。不同執行緒之間也無法直接訪問對方工作記憶體中的變數,執行緒間變數值的傳遞均需要通過主記憶體來完成。

基於此種記憶體模型,便產生了多執行緒程式設計中的資料“髒讀”等問題。

一:保證執行緒間的可見性 1)保證了不同執行緒對這個變數進行操作時的可見性,即一個執行緒修改了某個變數的值,這新值對其他執行緒來說是立即可見的。 2)禁止進行指令重排序 先看一段程式碼,假如執行緒1先執行,執行緒2後執行: //執行緒1 boolean stop = false ; while (!stop){     doSomething(); }   //執行緒2 stop = true ;
這段程式碼是很典型的一段程式碼,很多人在中斷執行緒時可能都會採用這種標記辦法。但是事實上,這段程式碼會完全執行正確麼?即一定會將執行緒中斷麼?不一定,也許在大多數時候,這個程式碼能夠把執行緒中斷,但是也有可能會導致無法中斷執行緒(雖然這個可能性很小,但是隻要一旦發生這種情況就會造成死迴圈了)。 下面解釋一下這段程式碼為何有可能導致無法中斷執行緒。在前面已經解釋過,每個執行緒在執行過程中都有自己的工作記憶體,那麼執行緒1在執行的時候,會將stop變數的值拷貝一份放在自己的工作記憶體當中。 那麼當執行緒2更改了stop變數的值之後,但是還沒來得及寫入主存當中,執行緒2轉去做其他事情了,那麼執行緒1由於不知道執行緒2對stop變數的更改,因此還會一直迴圈下去。
但是用volatile修飾之後就變得不一樣了: 第一:使用volatile關鍵字會強制將修改的值立即寫入主存; 第二:使用volatile關鍵字的話,當執行緒2進行修改時,會導致執行緒1的工作記憶體中快取變數stop的快取行無效(反映到硬體層的話,就是CPU的L1或者L2快取中對應的快取行無效); 第三:由於執行緒1的工作記憶體中快取變數stop的快取行無效,所以執行緒1再次讀取變數stop的值時會去主存讀取。 那麼線上程2修改stop值時(當然這裡包括2個操作,修改執行緒2工作記憶體中的值,然後將修改後的值寫入記憶體),會使得執行緒1的工作記憶體中快取變數stop的快取行無效,然後執行緒1讀取時,發現自己的快取行無效,它會等待快取行對應的主存地址被更新之後,然後去對應的主存讀取最新的值。 那麼執行緒1讀取到的就是最新的正確的值。 2.volatile不能確保原子性 volatile的應用場景 synchronized關鍵字是防止多個執行緒同時執行一段程式碼,那麼就會很影響程式執行效率,而volatile關鍵字在某些情況下效能要優於synchronized,但是要注意volatile關鍵字是無法替代synchronized關鍵字的,因為volatile關鍵字無法保證操作的原子性。通常來說,使用volatile必須具備以下2個條件: 1)對變數的寫操作不依賴於當前值 2)該變數沒有包含在具有其他變數的不變式中

原文:http://www.importnew.com/24082.html