天天看點

了解volatile

平時工作中對于多線程的應用并不太多,但是不能說工作中不應用就可以對此不去了解,至少要做的知道有這麼個東西,主要是作什麼的,這樣有助于看其它人寫的代碼。提到這個volatile,一般都會想到并發,同步,鎖之類,但要想搞清楚需要看看下面一些知識。

了解volatile
高速緩存的作用是什麼? 由于處理器與主記憶體在處理資料的速度上有數量級的差異,是以引入了比主記憶體速度更快的高速緩存。處理器從主記憶體中讀取資料放到高速緩存中做互動運算,最後回寫到主記憶體中。 引入高速緩存會帶來哪些問題?

使計算機系統更加複雜,但相對帶來的優點還是值得的。

緩存一緻性問題

多個處理器如果操作的是同一個主記憶體中的變量,那麼就會出現以誰為準的問題。這就要靠一些規定的協定來維護。

了解volatile

這是JAVA記憶體模型範疇,主要是用來屏蔽硬體與系統的記憶體通路差異,讓JAVA程式可以在不同的平台上達到相同的記憶體通路效果。

這裡說的工作記憶體,主記憶體與JVM記憶體中講的JAVA堆,棧,方法區不是同一層次上的概念,需要區分。

主要是工作記憶體與主記憶體之間的具體互動協定,即一個變量是如何從主記憶體加載到工作記憶體,然後從工作記憶體如何同步到主記憶體的具體實作細節,總共有以下幾個操作:

了解volatile

lock,辨別一個變量被某個變更獨占

write,将工作記憶體中的變量回寫到主記憶體中。這點是volatile的關鍵,它能夠保證被标記了volatile的變量一旦被修改馬上執行回寫主記憶體的操作,進而保證其它線程的可見性。

這三個特性是并發操作中需要處理的問題,volatile與下面兩個特性有關聯。是以在符合可見性以及有序性特性的場景就是volatile的适用場景,也是它的作用所在。

了解volatile

原子性

上面提到的記憶體互動操作中除了兩個鎖相關的都可以認為是原子性操作。

可見性

意思是說對于某個共享的變量,一個線程對其做了修改之後其它線程立馬可見。volatile在可見性方面上相對普通的變量有着重大差別,它能夠確定共享變量被修改後馬上執行回寫主記憶體的操作,而普通的變量做不到。

有序性

這裡有一個有意思的東西就是重排序,它的大體意思就是編寫的代碼順序不一定就是最終被處理器執行的順序,這是為了處理器内部的運算單元能夠盡量的被充分利用,有興趣的可以仔細研究下。而使用了volatile的變量能夠確定不被重排序,這是與普通變量不同的第二個重要差別。

運算的結果不依賴共享變量目前的值。

反例,多線程對volatile靜态變量執行累加。 這裡的count++看起來是一個語句,但對應的位元組碼不是一條,在執行多條位元組碼的期間主記憶體中的值有可能被其它線程所修改,進而導緻回寫到記憶體中的值不一緻。下面代碼的輸出并不總是正确。

下面是count++對應的位元組碼,很明顯是多條位元組碼。volatile隻能保證每次讀取變量的值是最新的,它在擷取到主記憶體變量後是對其副本進行修改,并不會鎖定主記憶體中的值。

某些共享的狀态變量是非常适合的,比如dubbo提供的accesslog filter。某些資源隻加載一次的場景特别适用,比如應用程式的配置檔案的加載,變量的初始化之類。

也不需要與其它的變量共同參與不變限制

由于volatile需要在修改變量時增加記憶體屏障語句,理所當然的相對沒有記憶體屏障語句的普通變量要慢一些。

volatile的特點是當線程對變量修改後馬上回與記憶體保證可見性,同時禁止重排序保證程式執行的有序性。由于它操作的是副本并不會對主記憶體加鎖,是以并不具體同步文法塊以及鎖的特點即可一時刻同一變量隻允許一個線程操作。

本文轉自帥氣的頭頭部落格51CTO部落格,原文連結http://blog.51cto.com/12902932/1924588如需轉載請自行聯系原作者

sshpp