Java 複習 —— JMM基礎

基本內容

一、共享變量在線程間的可見性安全

二、synchronized實現可見性多線程

三、volatile 實現可見性性能

1)指令重排序優化

2)as-if-serialspa

3)volatile 使用注意事項線程

四、volatile和synchronized的比較對象

一、可見性

一個線程對共享變量值的修改,可以及時地被其餘線程看到。排序

共享變量:若是一個變量在多個線程的工做內存中都存在副本,那麼這個變量就是這幾個線程的共享變量。內存

Java內存模型(JMM):描述了Java程序中各類變量(共享變量)的訪問規則,以及在JVM中將變量存儲到內存和從內存中讀取出變量這樣的底層細節。編譯器

二、JMM 基本規則

1)全部的變量都存儲在在主內存中。

2)每一個線程都有本身獨立的工做內存,裏面保存該線程使用到的變量副本(主內存中該變量的一份拷貝)。

3)線程對共享變量的全部操做都必須在本身的工做內存中進行,不能直接從主內存中讀寫

4)不一樣線程之間沒法直接訪問其餘線程工做內存中的變量,線程間變量值的傳遞須要經過主內存來完成。

三、共享變量實現可見性的原理

1)首先在本身線程Thread1裏修改共享變量x=1

2)而後更新主內存的x=1

3)其次其餘線程Thread2從主內存中讀取x=1,更新本身線程的值,

這樣連續性的操做,能夠保證任何一個線程的獨立內存中的共享變量都是最新的值!

四、Java層面實現可見性的方式

1)synchronized

2)volatile

3)concurrent 包

五、synchronized

1)線程解鎖前,必須把共享變量的最新值刷新到主內存中

2)線程加鎖時,將清空工做內存中共享變量的值,從而使用共享變量時須要從主內存中從新讀取最新的值。(注意:加鎖與解鎖須要同一把鎖)

六、synchronized 修飾時,JVM操做的步驟

1)首先得到互斥鎖

2)清空工做內存

3)從主內存拷貝變量的最新副本到工做內存

4)執行代碼

5)將更改後的共享變量值刷新到主內存

6)釋放互斥鎖

七、重排序

代碼書寫的順序與實際執行的順序不一樣,指令重排序是編譯器或處理器爲了提升程序性能而作的優化!

1)編譯器優化

2)指令優化

3)內存系統優化

最後的結果:有可能致使代碼的執行的順序與編寫順序不一致,可是能夠提升CPU性能

八、as-if-serial

不管如何重排序,程序的運行結果都是保持一致的!

單線程中是不能會由於重排序帶來內存可見性的問題。

多線程則會因爲重排序帶來共享變量不一致的問題。

九、致使共享變量在線程間不可見的緣由

1)線程交叉執行。(原子性來保證)

2)重排序結合線程交叉執行。(原子性來保證)

3)共享變量未及時更新。(內存可見性來保證)

十、synchronized 修飾變量、修飾方法或代碼塊

1)擁有原子性

2)擁有內存可見性

3)重量級

因此他可以實現線程間執行操做的安全性!

十一、volatile 修飾變量

1)不保證原子性

2)擁有可見性

3)輕量級

十二、關於 i++

1)首先讀取,從主內存中讀取i的值更新到當前工做內存中

2)其次改變,對i進行加1

3)最後更新,從當前工做內存中的值刷新到主內存中去

因此,這不是一個原子操做,在這個操做過程當中勢必會致使線程間交互而致使值的混亂!解決方式就是保證 i++ 具備原子性

1)使用synchronized

2)使用Lock對象,concurrent 包中

Lock lock = new RentrantLock();

try{

    lock.lock();

    i++

}finally{

    lock.unlock();

}

1三、volatile 使用場合

1)對變量的寫入操做不依賴其當前值,好比Boolean值,可是 i++ 或 i=i+5

2)該變量沒有包含在其餘變量的不變式中,好比: low < high (這裏我也不是很清楚)

注意:共享變量都必須是private

final 也實現了內存可見性,由於他的值是不可修改的!

1四、結論

對一個共享變量不只僅要關心他的寫,還關心他的讀,兩者都要加鎖;

volatile是輕量級的,能使用,儘可能使用!

相關文章
相關標籤/搜索