jvm內存模型(主存副本以及共享內存安全問題的產生以及synchronized線程安全原理和volatile關鍵字)

一:線程數據模型與安全:

           多核心(cpu)中,虛擬機是 一個主存 對應多個核心(cpu),一個cpu對應着多個內存副本,(可以理解爲主存對應着堆內存,而內存副本對應着各個cpu的線程所屬的內存,線程私有)。而一個線程取值時是從主存中取出複製到 副本中,而修改了值之後,會把修改後的值重新寫入主存,在這個過程中,由於各個線程都有不同的值,因此如果多線程只讀是沒問題的,但是讀寫混合操作時,各個線程就會產生線程安全問題。

    延伸:內存副本的數據修改後,會刷新到主存中,但是這個過程會有延遲,不是立刻就刷新數據,因此,使用volatile關鍵字,能強制將緩存的數據更新到主存中

二:volatile 關鍵字:

        使用 volatile 修改變量,會強制每個要讀取該變量的線程從主存中進行同步數據,保證數據是最新的。讀取時會進行刷新主存操作。但是這也只能保證讀取的數據是最新的,而不能使用此特性來進行數據併發安全的限制,因爲變量賦值等操作在併發下不是線程安全的,因此可能多個線程已經把數據搞亂了,但是最終數據總會是一個確定的值。

      原理:編譯後,volatile 會生成 Lock的字節碼指令,此指令會對變量所在緩存進行鎖定,多個cpu核心中的副本都保存有此變量的緩存,而 volatile 變量在修改時,會有兩步操作:1.直接將緩存數據同步到主存中 2.所有其他副本緩存的數據都會失效。是否失效是通過嗅探判斷 主線上 的內存是否已經失效,如果失效,會重新從主線上讀取最新數據,填充到緩存行中

三:synchronized 關鍵字:

       synchronized 關鍵字基於兩個實現,一個是同步方法,一個是同步代碼塊。共同點是 JVM基於進入和退出 Monitor對象來實現同步。代碼塊是使用 MonitorEnter 和 monitorExit指令實現。monitorenter是在編譯後插入到同步代碼塊的開始位置,而monitorexit是插入到方法結束處和異常處,兩指令是一一對應。任何對象都與一個monitor與之關聯,當且一個monitor被持有後,將處於鎖定狀態,線程執行到monitorenter指令時,將會嘗試獲取對象所對應的monitor的所有權,即嘗試獲取對象的鎖。

四:對象頭

       synchronized用的鎖是存在java對象頭裏的。數組對象,使用三個字寬存儲對象頭,非數組類型,使用兩個字寬(一字寬爲4字節,即32位),對象頭裏的 Mark Word 裏默認存儲對象的HashCode、分代年齡(應該至於方法區纔會對此進行計數)和鎖標誌位

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