Java 复习 —— JMM基础
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
基本內(nèi)容
1、共享變量在線程間的可見性
2、synchronized實(shí)現(xiàn)可見性
3、volatile 實(shí)現(xiàn)可見性
1)指令重排序
2)as-if-serial
3)volatile 使用注意事項(xiàng)
4、volatile和synchronized的比較
1、可見性
一個(gè)線程對(duì)共享變量值的修改,能夠及時(shí)地被其他線程看到。
共享變量:如果一個(gè)變量在多個(gè)線程的工作內(nèi)存中都存在副本,那么這個(gè)變量就是這幾個(gè)線程的共享變量。
Java內(nèi)存模型(JMM):描述了Java程序中各種變量(共享變量)的訪問規(guī)則,以及在JVM中將變量存儲(chǔ)到內(nèi)存和從內(nèi)存中讀取出變量這樣的底層細(xì)節(jié)。
2、JMM 基本規(guī)則
1)所有的變量都存儲(chǔ)在在主內(nèi)存中。
2)每個(gè)線程都有自己獨(dú)立的工作內(nèi)存,里面保存該線程使用到的變量副本(主內(nèi)存中該變量的一份拷貝)。
3)線程對(duì)共享變量的所有操作都必須在自己的工作內(nèi)存中進(jìn)行,不能直接從主內(nèi)存中讀寫
4)不同線程之間無法直接訪問其他線程工作內(nèi)存中的變量,線程間變量值的傳遞需要通過主內(nèi)存來完成。
3、共享變量實(shí)現(xiàn)可見性的原理
1)首先在自己線程Thread1里修改共享變量x=1
2)然后更新主內(nèi)存的x=1
3)其次其他線程Thread2從主內(nèi)存中讀取x=1,更新自己線程的值,
這樣連續(xù)性的操作,可以保證任何一個(gè)線程的獨(dú)立內(nèi)存中的共享變量都是最新的值!
4、Java層面實(shí)現(xiàn)可見性的方式
1)synchronized
2)volatile
3)concurrent 包
5、synchronized
1)線程解鎖前,必須把共享變量的最新值刷新到主內(nèi)存中
2)線程加鎖時(shí),將清空工作內(nèi)存中共享變量的值,從而使用共享變量時(shí)需要從主內(nèi)存中重新讀取最新的值。(注意:加鎖與解鎖需要同一把鎖)
6、synchronized 修飾時(shí),JVM操作的步驟
1)首先獲得互斥鎖
2)清空工作內(nèi)存
3)從主內(nèi)存拷貝變量的最新副本到工作內(nèi)存
4)執(zhí)行代碼
5)將更改后的共享變量值刷新到主內(nèi)存
6)釋放互斥鎖
7、重排序
代碼書寫的順序與實(shí)際執(zhí)行的順序不同,指令重排序是編譯器或處理器為了提高程序性能而做的優(yōu)化!
1)編譯器優(yōu)化
2)指令優(yōu)化
3)內(nèi)存系統(tǒng)優(yōu)化
最后的結(jié)果:有可能導(dǎo)致代碼的執(zhí)行的順序與編寫順序不一致,但是可以提高CPU性能
8、as-if-serial
無論如何重排序,程序的運(yùn)行結(jié)果都是保持一致的!
單線程中是不能會(huì)因?yàn)橹嘏判驇韮?nèi)存可見性的問題。
多線程則會(huì)由于重排序帶來共享變量不一致的問題。
9、導(dǎo)致共享變量在線程間不可見的原因
1)線程交叉執(zhí)行。(原子性來保證)
2)重排序結(jié)合線程交叉執(zhí)行。(原子性來保證)
3)共享變量未及時(shí)更新。(內(nèi)存可見性來保證)
10、synchronized 修飾變量、修飾方法或代碼塊
1)擁有原子性
2)擁有內(nèi)存可見性
3)重量級(jí)
所以他能夠?qū)崿F(xiàn)線程間執(zhí)行操作的安全性!
11、volatile 修飾變量
1)不保證原子性
2)擁有可見性
3)輕量級(jí)
12、關(guān)于 i++
1)首先讀取,從主內(nèi)存中讀取i的值更新到當(dāng)前工作內(nèi)存中
2)其次改變,對(duì)i進(jìn)行加1
3)最后更新,從當(dāng)前工作內(nèi)存中的值刷新到主內(nèi)存中去
所以,這不是一個(gè)原子操作,在這個(gè)操作過程中勢(shì)必會(huì)導(dǎo)致線程間交互而導(dǎo)致值的混亂!解決方式就是保證 i++ 具有原子性
1)使用synchronized
2)使用Lock對(duì)象,concurrent 包中
Lock lock = new RentrantLock();
try{
? ? lock.lock();
? ? i++
}finally{
? ? lock.unlock();
}
13、volatile 使用場(chǎng)合
1)對(duì)變量的寫入操作不依賴其當(dāng)前值,比如Boolean值,但是 i++ 或 i=i+5
2)該變量沒有包含在其他變量的不變式中,比如: low < high (這里我也不是很清楚)
注意:共享變量都必須是private
final 也實(shí)現(xiàn)了內(nèi)存可見性,因?yàn)樗闹凳遣豢尚薷牡?#xff01;
14、結(jié)論
對(duì)一個(gè)共享變量不僅僅要關(guān)心他的寫,還關(guān)心他的讀,二者都要加鎖;
volatile是輕量級(jí)的,能使用,盡量使用!
轉(zhuǎn)載于:https://my.oschina.net/heweipo/blog/505891
總結(jié)
以上是生活随笔為你收集整理的Java 复习 —— JMM基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux运维实战练习-2015年9月1
- 下一篇: Tom's Classes