1. 程式人生 > >volatile和synchronized 差別

volatile和synchronized 差別

int height 變更 spa http details 引用 復制 數據拷貝

1、什麽是volatile


Volatile修飾的成員變量在每次被線程訪問時,都強迫從共享內存中重讀該成員變量的值。並且,當成員變量發生變化時,強迫線程將變化值回寫到共享內存。這樣在不論什麽時刻,兩個不同的線程總是看到某個成員變量的同一個值。


Java語言規範中指出:為了獲得最佳速度。同意線程保存共享成員變量的私有拷貝。並且僅僅當線程進入或者離開同步代碼塊時才與共享成員變量的原始值對照。
這樣當多個線程同一時候與某個對象交互時,就必需要註意到要讓線程及時的得到共享成員變量的變化。


而volatilekeyword就是提示VM:對於這個成員變量不能保存它的私有拷貝,而應直接與共享成員變量交互


使用建議:在兩個或者很多其它的線程訪問的成員變量上使用volatile。

當要訪問的變量已在synchronized代碼塊中。或者為常量時。不必使用。


因為使用volatile屏蔽掉了VM中必要的代碼優化,所以在效率上比較低。因此一定在必要時才使用此keyword。


2、volatile和synchronized 差別

  1. volatile本質是在告訴jvm當前變量在寄存器中的值是不確定的,須要從主存中讀取,synchronized則是鎖定當前變量,僅僅有當前線程能夠訪問該變量,其它線程被堵塞住.
  2. volatile僅能使用在變量級別,synchronized則能夠使用在變量,方法.
  3. volatile僅能實現變量的改動可見性,但不具備原子特性,而synchronized則能夠保證變量的改動可見性和原子性.
  4. volatile不會造成線程的堵塞,而synchronized可能會造成線程的堵塞.
  5. volatile標記的變量不會被編譯器優化,而synchronized標記的變量能夠被編譯器優化.


引用:

http://blog.csdn.net/majorboy/article/details/475811

這個可能是最好的對照volatilesynchronized作用的文章了。

volatile是一個變量修飾符,而synchronized是一個方法或塊的修飾符。所以我們使用這兩種keyword來指定三種簡單的存取變量的方式。

int i1; int geti1() {return i1;}

volatile int i2; int geti2() {return i2;}

int i3; synchronized int geti3() {return i3;}

geti1()當前線程中馬上獲取在i1變量中的值。

線程能夠獲得變量的本地拷貝。而所獲得的變量的值並不一定與其它線程所獲得的值同樣。特別是。假設其它的線程改動了i1的值,那麽當前線程獲得的i1的值可能與改動後的值有所區別。實際上。Java有一種主內存的機制,使用一個主內存來保存變量當前的正確的值。線程將變量的值復制到自己獨立的內存中,而這些線程的內存拷貝可能與主內存中的值不同。

所以實際其中可能發生這種情況。在主內存中i1的值為1。線程1和線程2都更改了i1,可是卻沒把更新的值傳回給主內存或其它線程中,那麽可能在線程1i1的值為2,線程2i1的值卻為3

還有一方面,geti2()能夠有效的從主內存中獲取i2的值。一個volatile類型的變量不同意線程從主內存中將變量的值復制到自己的存儲空間。因此,一個聲明為volatile類型的變量將在全部的線程中同步的獲得數據,不論你在不論什麽線程中更改了變量,其它的線程將馬上得到相同的結果。

因為線程存取或更改自己的數據拷貝有更高的效率,所以volatile類型變量在性能上有所消耗。

那麽假設volatile變量已經能夠使數據在線程間同步。那麽synchronizes用來幹什麽呢?兩者有雙方面的不同。

首先。synchronized獲取和釋放由監聽器控制的鎖。假設兩個線程都使用一個監聽器(即同樣對象鎖)。那麽監聽器能夠強制在一個時刻僅僅有一個線程能處理代碼塊。這是最一般的同步。

另外。synchronized還能使內存同步。在實際其中。synchronized使得全部的線程內存與主內存同樣步。所以geti3()的運行步驟例如以下:

1. 線程從監聽器獲取對象的鎖。(這裏如果監聽器非鎖,否則線程僅僅有等到監聽器解鎖才幹獲取對象鎖)

2. 線程內存更新全部的變量。也就是說他將讀取主內存中的變量使自己的變量保證有效。

(JVM會使用一個“臟”標誌來最優化過程。使得只具有“臟”標誌變量被更新。具體的情況查詢JAVA規範的17.9)

3. 代碼塊被運行(在這個樣例中,設置返回值為剛剛從主內存重置的i3當前的值。

)

4. 不論什麽變量的變更將被寫回到主內存中。可是這個樣例中geti3()沒有什麽變化。

5. 線程釋放對象的鎖給監聽器。

所以volatile僅僅能在線程內存和主內存之間同步一個變量的值,而synchronized則同步在線程內存和主內存之間的全部變量的值,而且通過鎖住和釋放監聽器來實現。

顯然,synchronized在性能上將比volatile更加有所消耗。



volatile和synchronized 差別