Volatile內部原理

前言:多線程內存的劃分分爲:java線程、工作內存、save和load操作、主內存

volatile內部原理

volatile變量賦值後,彙編代碼會多一個lock操作,相當於內存屏障,作用是使本CPU的緩存寫入內存(相當於store和write操作),該寫入動作會使其他cpu的緩存無效,所以valatile變量的修改對其它cpu立即可見。

 

volatile的變量新增的內存語義

1、工作內存中,每次使用使用對象前必須先從主內存刷新最新的值。(其它cpu能看到變量最新的值)

2、工作內存中,每次修改變量後必須立刻同步會主內存中。(其它線程可以看到本線程對變量的修改)

3、volatile修飾的變量不會被指令從排序優化。(a肯定在b之前執行)

volatile boolean a;

int i=3;

int j=5;

volatile boolean b;

 

volatile作用

1、只能保證變量對所有線程的可見性,不能保證原子性和有序性。

2、每次使用前,都要先刷新,執行引擎看不到不一致的情況,因此可以認爲不存在一致性的問題。

3、使用Volatile變量會禁止指令重排序優化,其實就是內存屏障的作用,(volatile前的代碼不會在volatile變量之後執行,volatile變量之後的代碼也不會在volatile變量之前執行),保證代碼的執行順序與程序的順序相同。

4、每次使用變量前必須從主內存刷新最新的值,每次修改變量後必須立刻同步回主內存中。

5、目前商用虛擬機幾乎都把64位的數據讀寫操作作爲原子操作來對待。

 

JMM有8種原子的內存語義操作

1、lock(鎖定):作用於主內存的變量,它把一個變量標識爲一條線程獨佔的狀態。

2、unlock(解鎖):作用於主內存的變量,它吧一個處於鎖定狀態的變量釋放出來,釋放後的變量才能被其它線程鎖定。

3、read(讀取):作用於主內存的變量,它把一個變量的值從主內存傳輸到線程的工作內存中,以便隨後的load作用。

4、load(載入):作用於工作內存的變量,它把read操作從主內存中得到的變量值放入到工作內存的變量副本中。

5、assign(賦值):作用於工作內存的變量,它把一個從執行引擎接收到的值賦給工作內存的變量。

6、store(存儲):作用於工作內存的變量,把工作內存的變量傳到主內存中,以便隨後write操作。

7、write(寫入):作用於主內存的變量,把store操作從工作內存中的變量放到主內存中。

 

JMM的8中基本操作必須滿足的規則

1、不允許read和load、store和write操作之一單獨出現

2、發生過assign操作,必須把變量在工作內存改變後必須同步會主內存(同步的時間點不一定)

3、沒有發生過assign操作,不允許把數據從工作內存同步回主內存

4、新變量只能從主內存誕生

5、一個變量同一時刻只允許一個線程對其進行lock操作,但可被同一線程多次lock,lock幾次就要unlock幾次(synchronized同步代碼塊原理實現方式)

6、一個變量執行lock操作會清空工作內存中該變量的值

7、變量沒有執行lock操作則不能執行unlock操作

8、對變量執行unlock前,必須把此變量同步回主內存(synchronized同步塊可見性實現原理)

 

原子性

1、基本數據類型的訪問讀寫是具備原子性的

2、lock和unlock操作沒有開放個用戶直接使用,但是提供了更高級別的字節碼指令monitorenter和monitorexit,也就是java中的synchronized快

可見性

1、synchronized和final關鍵字也具有可見性

2、synchronized可見性是因爲,對一個變量執行unlock前,必須先把變量同步回主內存中(執行store和write操作)這條獲得的。

3、final可見性,被final修飾的字段在構造器中一旦初始化完成,其它線程就能看見該字段的值。

有序性

1、synchronized的有序性是通過 一個變量在同一時刻只允許一個線程對其進行lock操作 獲得的。

 

先行先發原則的作用

判斷數據是否存在競爭,線程是否安全的依據。

JMM中的順序性不能僅僅依靠volatile和synchronized.

先行發生原則和時間的先後順序沒什麼關係

什麼是先行先發原則

A操作先行發生於B操作,那A操作的影響能被B操作觀察到。(影響包括內存共享變量值的改變、發送消息、調用方法等)

1、程序次序:一個線程內,按照程序代碼的順序,寫在前面的操作先行發生於後面的操作。

2、synchronized相關:unlock先於後面的lock

一個unlock操作先行發生於後面對同一個鎖的lock操作。(後面只時間的先後)

3、volatile相關:寫先於讀

對volatile的寫操作先行發生於後面對這個變量的讀操作。(後面只時間的先後)

線程相關

4、start():Thread的start()方法先行發生於此線程的每一個動作。(start()先於所有動作)

5、join()或isAlive():線程中的所有操作先行發生於對此線程的終止檢驗(所有動作先於Thread.join方法結束、Thread.isAlive等)

6、interrupt():線程中斷先行發生於對中斷檢驗代碼(interrupt()先於Thread.interrupted())

7、finalize():初始化方法的完成先於finalize()的開始

8、傳遞性:A操作先於B操作,B操作先於C操作,那A操作先於C操作。

 

 

 

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