volatile的應(yīng)用
-
valatile實(shí)現(xiàn)原則
- Lock前綴指令會引起處理器緩存回寫到內(nèi)存
- 一個處理器的緩存回寫到內(nèi)存會導(dǎo)致其他處理器的緩存無效
-
volatile的使用優(yōu)化
- 追加字節(jié)
64字節(jié)的方式來優(yōu)化性能(Java 7下可能不生效,采用了其他追加字節(jié)的方式)
- 追加字節(jié)
synchronized的實(shí)現(xiàn)原理與應(yīng)用
相信絕大數(shù)人在腦海里對synchronized的第一印象就是重量級鎖,性能消耗特別高,不到萬不得一最好不要使用synchronized,當(dāng)然了,在1.6版本之前確實(shí)是這樣的,但是在1.6版本對synchronized進(jìn)行了優(yōu)化,其中最主要的就是引入了偏向鎖、輕量級鎖。后續(xù)會有所提及。
- 對于普通同步方法,鎖是當(dāng)前實(shí)例對象
- 對于靜態(tài)同步方法,鎖是當(dāng)前類的Class對象
- 對于同步方法塊,鎖是synchronized括號里配置的對象
記住synchronized是通過JVM實(shí)現(xiàn)的,如果修飾的同步塊,與之對應(yīng)的命令monitorenter和monitorexit。如果是同步方法,則是依靠方法修飾符上的ACC_SYNCHRONIZED
- Java對象頭
Java對象頭的存儲結(jié)構(gòu)(32位JVM)
| 鎖狀態(tài) | 25bit | 4bit | 1bit(偏向鎖) | 2bit(鎖標(biāo)志位) |
|---|---|---|---|---|
| 無鎖狀態(tài) | 對象的hashCode | 對象分代年齡 | 0 | 01 |
Java對象頭的存儲結(jié)構(gòu)(64位JVM)
不支持HTML標(biāo)簽,只能截圖了

image.png
- 鎖級別(由低到高)
無鎖狀態(tài)->偏向鎖狀態(tài)->輕量級鎖狀態(tài)->重量級鎖狀態(tài)(只能升級不能降級)
偏向鎖
初次獲取鎖的時候,將自身的ThreadID寫入到mark word的ThreadId字段內(nèi),并且將偏向鎖的狀態(tài)置為1。如果再有線程來獲取鎖的時候,直接比較ThreadID是否一致。
輕量級鎖
兩個線程競爭,其中只會有一個競爭成功,另外一個進(jìn)行自旋CAS。
鎖的優(yōu)缺點(diǎn)對比及適用場景
| 鎖 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場景 |
|---|---|---|---|
| 偏向鎖 | 加鎖和解鎖不需要額外的消耗,和執(zhí)行非同步方法相比僅存在納秒級的差距 | 如果線程間存在鎖競爭,會帶來額外的鎖撤銷的消耗 | 使用只有一個線程訪問同步塊場景 |
| 輕量級鎖 | 競爭的線程不會阻塞,提高了程序的響應(yīng)速度 | 如果始終得不到鎖競爭的線程,使用自旋會消耗CPU | 追求響應(yīng)時間,同步塊執(zhí)行速度非???/td> |
| 重量級鎖 | 線程競爭不適用自旋,不會消耗CPU | 線程阻塞,響應(yīng)時間緩慢 | 追求吞吐量,同步塊執(zhí)行速度較長 |
原子操作的實(shí)現(xiàn)原理
-
如何實(shí)現(xiàn)原子性
- 使用總線鎖保證原子性(使用處理器提供的Lock #信號,當(dāng)一個處理器在總線上輸出此信號時,其他處理器的請求將被阻塞住,所以開銷比較大)
- 使用緩存鎖保證原子性(修改內(nèi)部的內(nèi)存地址,通過緩存一致性機(jī)制來保證操作的原子性,因為緩存一致性機(jī)制會阻止同時修改由兩個以上處理器緩存的內(nèi)存區(qū)域數(shù)據(jù),當(dāng)其他處理器回寫已被鎖定的緩存行的數(shù)據(jù)時,會使緩存行無效)
- 有兩種特殊情況處理器不會使用緩存鎖定
- 當(dāng)操作的數(shù)據(jù)不能被緩存在處理器內(nèi)部或操作的數(shù)據(jù)跨多個緩存行時,則會調(diào)用總線鎖定
- 有些處理器不支持緩存鎖定。(Intel 486和Pentium處理器)
- 有兩種特殊情況處理器不會使用緩存鎖定
-
Java如何實(shí)現(xiàn)原子操作
- 實(shí)現(xiàn)方式
- 鎖
- 自旋CAS
- 鎖機(jī)制實(shí)現(xiàn)原子操作
JVM內(nèi)部多種鎖機(jī)制:偏向鎖、輕量級鎖、互斥鎖。除了偏向鎖,其它都用到了CAS - CAS實(shí)現(xiàn)原理及存在的問題
- JVM中的CAS操作是利用處理器提供的CMPXCHG指令實(shí)現(xiàn)的
- CAS實(shí)現(xiàn)原子操作的三大問題
- ABA問題(1.5版本提供的AtomicStampedReference來解決的)
- 循環(huán)時間長,開銷大(如果處理器支持pause命令,效率有所提升。第一,延遲流水線執(zhí)行命令,使CPU不會消耗過多的執(zhí)行資源。第二,避免循環(huán)推出的時候因內(nèi)存順序沖突而引起CPU流水線被清空,從而提高CPU的執(zhí)行效率)
- 只能保證一個共享變量的原子操作(1.5版本提供的AtomicReference類來保證引用對象之間的原子性,就可以把多個變量放在一個對象里來進(jìn)行CAS操作)
- 實(shí)現(xiàn)方式