volatile的應(yīng)用
-
valatile實(shí)現(xiàn)原則
- Lock前綴指令會(huì)引起處理器緩存回寫到內(nèi)存
- 一個(gè)處理器的緩存回寫到內(nèi)存會(huì)導(dǎo)致其他處理器的緩存無效
-
volatile的使用優(yōu)化
- 追加字節(jié)
64字節(jié)
的方式來優(yōu)化性能(Java 7下可能不生效褥伴,采用了其他追加字節(jié)的方式)
- 追加字節(jié)
synchronized的實(shí)現(xiàn)原理與應(yīng)用
相信絕大數(shù)人在腦海里對(duì)synchronized的第一印象就是重量級(jí)鎖濒翻,性能消耗特別高牵寺,不到萬不得一最好不要使用synchronized疼进,當(dāng)然了焦匈,在1.6版本之前確實(shí)是這樣的,但是在1.6版本對(duì)synchronized進(jìn)行了優(yōu)化,其中最主要的就是引入了偏向鎖、輕量級(jí)鎖雀鹃。后續(xù)會(huì)有所提及。
- 對(duì)于普通同步方法励两,鎖是當(dāng)前實(shí)例對(duì)象
- 對(duì)于靜態(tài)同步方法黎茎,鎖是當(dāng)前類的Class對(duì)象
- 對(duì)于同步方法塊,鎖是synchronized括號(hào)里配置的對(duì)象
記住synchronized是通過JVM實(shí)現(xiàn)的当悔,如果修飾的同步塊傅瞻,與之對(duì)應(yīng)的命令monitorenter
和monitorexit
。如果是同步方法盲憎,則是依靠方法修飾符上的ACC_SYNCHRONIZED
- Java對(duì)象頭
Java對(duì)象頭的存儲(chǔ)結(jié)構(gòu)(32位JVM)
鎖狀態(tài) | 25bit | 4bit | 1bit(偏向鎖) | 2bit(鎖標(biāo)志位) |
---|---|---|---|---|
無鎖狀態(tài) | 對(duì)象的hashCode | 對(duì)象分代年齡 | 0 | 01 |
Java對(duì)象頭的存儲(chǔ)結(jié)構(gòu)(64位JVM)
不支持HTML標(biāo)簽嗅骄,只能截圖了
- 鎖級(jí)別(由低到高)
無鎖狀態(tài)->偏向鎖狀態(tài)->輕量級(jí)鎖狀態(tài)->重量級(jí)鎖狀態(tài)(只能升級(jí)不能降級(jí))
偏向鎖
初次獲取鎖的時(shí)候,將自身的ThreadID寫入到mark word的ThreadId字段內(nèi)饼疙,并且將偏向鎖的狀態(tài)置為1掸读。如果再有線程來獲取鎖的時(shí)候,直接比較ThreadID是否一致宏多。
輕量級(jí)鎖
兩個(gè)線程競(jìng)爭,其中只會(huì)有一個(gè)競(jìng)爭成功澡罚,另外一個(gè)進(jìn)行自旋CAS伸但。
鎖的優(yōu)缺點(diǎn)對(duì)比及適用場(chǎng)景
鎖 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場(chǎng)景 |
---|---|---|---|
偏向鎖 | 加鎖和解鎖不需要額外的消耗,和執(zhí)行非同步方法相比僅存在納秒級(jí)的差距 | 如果線程間存在鎖競(jìng)爭留搔,會(huì)帶來額外的鎖撤銷的消耗 | 使用只有一個(gè)線程訪問同步塊場(chǎng)景 |
輕量級(jí)鎖 | 競(jìng)爭的線程不會(huì)阻塞更胖,提高了程序的響應(yīng)速度 | 如果始終得不到鎖競(jìng)爭的線程,使用自旋會(huì)消耗CPU | 追求響應(yīng)時(shí)間隔显,同步塊執(zhí)行速度非橙捶粒快 |
重量級(jí)鎖 | 線程競(jìng)爭不適用自旋,不會(huì)消耗CPU | 線程阻塞括眠,響應(yīng)時(shí)間緩慢 | 追求吞吐量彪标,同步塊執(zhí)行速度較長 |
原子操作的實(shí)現(xiàn)原理
-
如何實(shí)現(xiàn)原子性
- 使用總線鎖保證原子性(使用處理器提供的Lock #信號(hào),當(dāng)一個(gè)處理器在總線上輸出此信號(hào)時(shí)掷豺,其他處理器的請(qǐng)求將被阻塞住捞烟,所以開銷比較大)
- 使用緩存鎖保證原子性(修改內(nèi)部的內(nèi)存地址薄声,通過緩存一致性機(jī)制來保證操作的原子性,因?yàn)榫彺嬉恢滦詸C(jī)制會(huì)阻止同時(shí)修改由兩個(gè)以上處理器緩存的內(nèi)存區(qū)域數(shù)據(jù)题画,當(dāng)其他處理器回寫已被鎖定的緩存行的數(shù)據(jù)時(shí)默辨,會(huì)使緩存行無效)
- 有兩種特殊情況處理器不會(huì)使用緩存鎖定
- 當(dāng)操作的數(shù)據(jù)不能被緩存在處理器內(nèi)部或操作的數(shù)據(jù)跨多個(gè)緩存行時(shí),則會(huì)調(diào)用總線鎖定
- 有些處理器不支持緩存鎖定苍息。(Intel 486和Pentium處理器)
- 有兩種特殊情況處理器不會(huì)使用緩存鎖定
-
Java如何實(shí)現(xiàn)原子操作
- 實(shí)現(xiàn)方式
- 鎖
- 自旋CAS
- 鎖機(jī)制實(shí)現(xiàn)原子操作
JVM內(nèi)部多種鎖機(jī)制:偏向鎖缩幸、輕量級(jí)鎖、互斥鎖竞思。除了偏向鎖表谊,其它都用到了CAS - CAS實(shí)現(xiàn)原理及存在的問題
- JVM中的CAS操作是利用處理器提供的CMPXCHG指令實(shí)現(xiàn)的
- CAS實(shí)現(xiàn)原子操作的三大問題
- ABA問題(1.5版本提供的AtomicStampedReference來解決的)
- 循環(huán)時(shí)間長,開銷大(如果處理器支持pause命令衙四,效率有所提升铃肯。第一,延遲流水線執(zhí)行命令传蹈,使CPU不會(huì)消耗過多的執(zhí)行資源押逼。第二,避免循環(huán)推出的時(shí)候因內(nèi)存順序沖突而引起CPU流水線被清空惦界,從而提高CPU的執(zhí)行效率)
- 只能保證一個(gè)共享變量的原子操作(1.5版本提供的AtomicReference類來保證引用對(duì)象之間的原子性挑格,就可以把多個(gè)變量放在一個(gè)對(duì)象里來進(jìn)行CAS操作)
- 實(shí)現(xiàn)方式