java編程,如何徹底理解volatile關鍵字?

黃元中


volatile在Java語言中扮演者重要的角色,它具有可見性以及禁止指令重排序兩個非常顯著的特點,要想解釋清楚volatile的用法,首先我們要對Java的內存模型JMM有一個非常熟悉的瞭解,所以我從以下幾點來分析volatile。

一、Java內存模型JMM

Java的內存模型規定:所有的變量都保存在主內存中,每一個線程都有屬於自己的工作內存,當讀取主內存的變量時,線程的工作內存都會都會存儲這個變量的副本,線程對變量的操作都是在自己的工作內存中,在適當的時候會把自己工作內存的變量同步到主內存中。

從上面的內容中可以得出一個結論,多線程對變量的修改,都是先修改自己的工作內存的變量,然後把工作內存中修改的在適當的時候同步到主內存中,那麼問題就來了,適當的時候是什麼時候呢?不確定,所以就有問題了,當主內存中有一個變量i=0,假如同時有兩個線程去修改i的值,當線程1讀取主內存中的i=1,然後拷貝一份副本在自己的工作內存中,然後i=1,但是這是操作的自己的工作內存i=1,但是這個i=1什麼時候刷新到主內存中呢?剛才我們說了,不確定,此時線程二讀取主存的變量i=0,然後也拷貝一份到自己的工作內存中,然後i=2,然後在適當的時候刷新到主存中,所以最終的結果可能是線程二i=2的結果先刷新到主存中,線程一i=1最後刷新到主存中,這就導致現在主存中i=1,所以與想象的結果不一樣。

二、volatile的大白話

瞭解了Java的內存模型JMM,我們瞭解了對於一個共享變量,如果有多個線程併發的修改這個共享變量,最終得到的結果可能與我們想象的不太一樣,這是由於JMM的機制導致的,而這和我們所說的volatile有什麼關係的,那接下來我們就說說。

結論:1:如果一個變量被volatile修飾,那麼它在工作內存中修改的變量會立刻被刷新到主存中。而不是上面所說的不確定的時候

2:如果讀取一個被volatile修飾的變量,會把此線程工作內存中的此變量副本置為無效,它會從主內存中重新讀取這個變量到自己的工作內存。

上面這兩點分別是volatile寫內存語義和volatile內存語義。

三、volatile在JDK的使用

在JDK中,併發包中volatile把它的特點發揮到了極致,尤其通過框架AQS的state就是被volatile修飾的,在加上CAS構建出了無鎖化的同步框架,在ConcurrentHashMap中也是因為有了volatile的作用加上CAS操作提高了很大的性能。

上面3點只是簡單的說明了volatile的作用,如果要詳細介紹volatile,估計能夠一本上百頁的書了,在這裡就不再詳述了,如果想進一步瞭解volatile,請關注我的頭條,我會有一個關於volatile的專題。


強哥Java架構之路


非java程序員,不過volatile在其他語言中也存在,簡單說下。

1,volatile只在多線程程序中有意義。

2,為了提高性能,編譯器工作時會進行一些優化,如指令排序,甚至跳過一些指令。如:

var a=1;

a=2;

a=3;

編譯後的結果可能就只執行 a = 3

3,程序運行時,普通變量會有緩存機制(如cpu緩存、線程本地緩存等),程序讀取時先從緩存讀取,所以多線程的程序運行時可能存在髒讀問題。即第一個線程已經修改了變量值,但第二個線程還在使用緩存中的舊數據。

volatile的作用就是告訴編譯器,不要對使用該變量的代碼進行優化,每次讀寫操作都訪問變量的原始數據。


xdm99


通常程序不會直接去操作CPU內核線程,而是通過內核線程的接口輕量級進程(LWP)來操作的,也就是通常意義上的線程.


系統在執行多線程任務時,數據存儲在RAM中,然而每個線程都有一個本地緩存,也就是CPU緩存,並不會每次都從RAM讀取數據,所以就會出現線程不安全的情況。

Java中volatile關鍵字主要是用來修飾變量使其能夠被線程可見.


飛昇的碼農


https://m.toutiaocdn.com/group/6682538998579069453/?app=news_article×tamp=1556016557&req_id=201904231849160100160441948694FA8&group_id=6682538998579069453

參考這篇文章


huJeson


建議先學習java內存模型以及指令重排序,如此就能真正理解


分享到:


相關文章: