33、volatile

在實際項目使用並不多,但是容易出錯。很多人感覺和synchronized差不多,實際上完全不一樣。我們看一下兩者的區別:

volatile保證程序的可見性,這個和synchronize的區別就非常大,首先volatile他並不保證原子性。synchronized可以保證原子性,

什麼叫原子性呢? 就是多個線程同時操作一個數據或則方法時,他們沒有辦法同時操作,只有一個操作完畢,另一個才能操作。

什麼是可見性呢?線程在訪問這樣一個變量的時候,他都會去讀取最新的值,即便被其他線程修改了。

volatile保證可見性,他的實現原理:內存直讀,禁止指令重排序。

內存直讀就是每次都從內存中讀取,不會走任何的緩存。這樣可以保證每次讀到的都是新的。

因爲變量發生變化的時候,就是內存對應某個地址的值發生變化,不管任何線程去操作,每次都從內存地址裏面去讀出來的數肯定是在這個時刻最新的值。

那什麼情況下會發生讀到老的數據呢

cpu有自己的緩存和寄存器,從內存中拿到數據,然後放到緩存或則寄存器裏面處理,這樣就有一個時間差。

比如我們有一個數據在沒有讀到cpu緩存之前就有其他線程來讀取,那麼他讀取到的是什麼呢?是緩存中老的值,還沒有同步。

非volatile是從緩存裏面讀,讀了再執行,可能被修改

volatile變量直接去內存裏面找。保證每次都讀最新的。

 

禁止重排序

首先我們看下什麼是cpu指令的重排序,cpu允許將多條指令,不按照程序規定的順序來執行。我們知道cpu執行會把多條指令進行一定的優化,把他拆成若干塊,然後把各部分發給相應的電路單元來處理。A=B B=C c=A  A=B B=C  其實cpu只執行兩句  A=b  b=c  其他的可能會被優化掉  

比如,我們new 一個對象,你認爲先分配一個塊內存地址,再去new 對象,有可能是找到一塊緩存區,先構造了一個對象,然後在分配地址,然後在分配指向。和我們想的不一樣。

禁止重排序就是,在讀取地址內容的時候,在最後增加了一句,內存屏障,他告訴cpu,不允許把這後面內存排到他之前。保證了前面都是有序的。

synchronized 

既可以保證可見性,又能夠保證原子性。

可見性體現在:通過synchronized或者Lock能保證同一時刻只有一個線程獲取鎖然後執行同步代碼,並且在釋放鎖之前會將對變量的修改刷新到主存中。

原子性表現在:要麼不執行,要麼執行到底。

雖然效率比synchronized高,但是容易出粗,不好排查錯誤,但是不推薦使用。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章