JAVA volatile關鍵字

     Java中volatile關鍵字原義是“不穩定、變化”的意思,那麼在java語言中,volatile是什麼意思呢?

     volatile,在Java中用來修飾變量,那是爲什麼呢?volatile是告訴jvm,這個變量不能被私自佔有使用,下面就解釋一下爲什麼這麼說吧!

     大家都知道,在java中,除了long和double的操作,對基本類型的操作是原子性的,那還爲什麼使用valotile關鍵字呢,因爲隨着jvm的優化和成熟,爲了提高多線程的效率,允許每個線程在工作內存保存變量的拷貝進行操作,這就很容易出現數據不一致,所以volatile就強制是多核或多線程必須從主存中讀寫變量,保證變量的一致性

     由於比起synchronized,volatile關鍵字的覆蓋範偉更小,只是修飾的變量,所以效率就比前者高,但是,它是存在問題的,不能保證“線程寫的合理”,解釋如下:寫的不合理,是可能存在競爭條件,而出現操作與設想結果不同。volatile變量在併發下不安全

     假如,有100個線程正在對一個i變量驚醒i++操作,那麼結果一定是100麼,可能<100的,比如一個線程a讀到的是i=3,幾乎同時(a沒有修改i),另一個線程也讀到3,那麼結果,兩次相加就得到了i=4,而不是5,詳細看看操作系統同步就知道了。

     volatile關鍵字有什麼用?恐怕比較一下volatile和synchronized的不同是最容易解釋清楚的。volatile是變量修飾符,而synchronized則作用於一段代碼或方法;看如下三句get代碼:
     int i1;                  int geti1() {return i1;}
     volatile int i2;         int geti2() {return i2;}
     int i3; synchronized     int geti3() {return i3;}

  geti1()得到存儲在當前線程中i1的數值。多個線程有多個i1變量拷貝,而且這些i1之間可以互不相同。換句話說,另一個線程可能已經改變了它線程內的i1值,而這個值可以和當前線程中的i1值不相同。事實上,Java有個思想叫“主”內存區域,這裏存放了變量目前的“準確值”。每個線程可以有它自己的變量拷貝,而這個變量拷貝值可以和“主”內存區域裏存放的不同。因此實際上存在一種可能:“主”內存區域裏的i1值是1,線程1裏的i1值是2,線程2裏的i1值是3——這在線程1和線程2都改變了它們各自的i1值,而且這個改變還沒來得及傳遞給“主”內存區域或其他線程時就會發生。
  而geti2()得到的是“主”內存區域的i2數值。用volatile修飾後的變量不允許有不同於“主”內存區域的變量拷貝。換句話說,一個變量經volatile修飾後在所有線程中必須是同步的;任何線程中改變了它的值,所有其他線程立即獲取到了相同的值。理所當然的,volatile修飾的變量存取時比一般變量消耗的資源要多一點,因爲線程有它自己的變量拷貝更爲高效。
  既然volatile關鍵字已經實現了線程間數據同步,又要synchronized幹什麼呢?呵呵,它們之間有兩點不同。首先,synchronized獲得並釋放監視器——如果兩個線程使用了同一個對象鎖,監視器能強制保證代碼塊同時只被一個線程所執行——這是衆所周知的事實。但是,synchronized也同步內存:事實上,synchronized在“主”內存區域同步整個線程的內存。因此,執行geti3()方法做了如下幾步:

1. 線程請求獲得監視this對象的對象鎖(假設未被鎖,否則線程等待直到鎖釋放)

2. 線程內存的數據被消除,從“主”內存區域中讀入(Java虛擬機能優化此步。。。[後面的不知道怎麼表達,汗])

3. 代碼塊被執行

4. 對於變量的任何改變現在可以安全地寫到“主”內存區域中(不過geti3()方法不會改變變量值)

5. 線程釋放監視this對象的對象鎖

  因此volatile只是在線程內存和“主”內存間同步某個變量的值,而synchronized通過鎖定和解鎖某個監視器同步所有變量的值。顯然synchronized要比volatile消耗更多資源

發佈了15 篇原創文章 · 獲贊 9 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章