java 底層提供的一種同步機(jī)制(關(guān)鍵字)
可重入(偏向鎖時(shí) 當(dāng)前線(xiàn)程可重入)
異常會(huì)釋放鎖,如果不想被釋放,可以catch異常
鎖信息只能存儲(chǔ)在對(duì)象(實(shí)例)上
使用對(duì)象做鎖,一定要加final,對(duì)象的屬性發(fā)生變化不影響鎖的使用,但是定義發(fā)生改變會(huì)導(dǎo)致原來(lái)的鎖失效 例如重新 o = new Object();
//鎖信息存儲(chǔ)在調(diào)用t1方法的實(shí)例上
public synchronized void t1(){}
public void t2(){
//鎖信息存儲(chǔ)在當(dāng)前實(shí)例上
synchronized(this){ }
final Object o = new Object();
//鎖信息存儲(chǔ)在實(shí)例o上
synchronized(o){}
//鎖信息存儲(chǔ)在實(shí)例Object的對(duì)象上,俗稱(chēng)類(lèi)鎖,
//jvm 加載Object類(lèi)時(shí),會(huì)自動(dòng)劃分一塊內(nèi)存,生成Object類(lèi)的對(duì)象
synchronized(Object.class){}
}
//鎖信息存儲(chǔ)在t3方法所處類(lèi)的對(duì)象上,俗稱(chēng)類(lèi)鎖
public synchronized static void t3(){}
實(shí)現(xiàn)過(guò)程
- java代碼: 加 synchronize
- 字節(jié)碼層級(jí): monitorenter moniterexit
- 執(zhí)行過(guò)程: 自動(dòng)升級(jí)鎖
- 匯編層級(jí): lock comxchg
鎖升級(jí)
參考
- java對(duì)象內(nèi)存模型
鎖信息.png
新new對(duì)象 -> 偏向鎖 -> 輕量級(jí)鎖(無(wú)鎖 ,自旋鎖.自適應(yīng)鎖) ->重量級(jí)鎖
- 無(wú)鎖: 新new對(duì)象
- 偏向鎖: 第一次拿鎖時(shí)上的是偏向鎖,鎖信息為當(dāng)前線(xiàn)程id號(hào),當(dāng)前線(xiàn)程可重入
- 輕量級(jí)鎖: 發(fā)送任意競(jìng)爭(zhēng),撤銷(xiāo)偏向鎖,上輕量級(jí)鎖,使用自旋的方式(CAS)競(jìng)爭(zhēng)鎖.
- 重量級(jí)鎖:jdk1.6以下:自旋超過(guò)10次,cpu等待核數(shù)>1/2,1.6之后加入自適應(yīng)自旋,jvm自己控制,自動(dòng)升級(jí)(向操作系統(tǒng)申請(qǐng)).
ps:
輕量級(jí)鎖在自旋拿鎖,不停的循環(huán),特別消耗cpu,每個(gè)重量級(jí)鎖都擁有一個(gè)隊(duì)列,等待執(zhí)行的線(xiàn)程會(huì)進(jìn)入wait狀態(tài),不消耗cpu
用戶(hù)態(tài): 應(yīng)用程序可以使用的資源
內(nèi)核態(tài): 使用硬件資源必須通過(guò)內(nèi)核執(zhí)行,比如拿鎖,向顯卡寫(xiě)入數(shù)據(jù)等
鎖降級(jí)
重量級(jí)鎖的降級(jí)發(fā)生于STW(執(zhí)行垃圾收集算法)階段,降級(jí)對(duì)象就是那些僅僅能被VMThread訪(fǎng)問(wèn)而沒(méi)有其他JavaThread訪(fǎng)問(wèn)的對(duì)象。因此沒(méi)有什么意義,可以認(rèn)為沒(méi)有鎖降級(jí)
鎖消除
當(dāng)jvm發(fā)現(xiàn)某有鎖對(duì)象的引用只能被單一線(xiàn)程使用時(shí)(局部變量,棧私有),會(huì)自動(dòng)消除對(duì)象內(nèi)部的鎖,例如以下情況就無(wú)鎖
public void add (String str1,String str2){
StringBuffer sb = new StringBuffer();
//會(huì)自動(dòng)消除append方法上的鎖
sb.append(str1).appand(str2);
}
鎖粗化
當(dāng)jvm發(fā)現(xiàn)一連串的操作都對(duì)同一對(duì)象加鎖,jvm就會(huì)將加鎖的范圍粗化到這一連串操作的外部(如while),使得一連串操作只需要加一次鎖
private static StringBuffer sb = new StringBuffer();
public static void test (String str){
sb.clear();
while(i<100){ //會(huì)自動(dòng)消粗化到while虛幻體外部
sb.append(str);
i++;
}
}
synchronized vs CAS
- 在高爭(zhēng)用 高耗電的環(huán)境下 synchronize 效率更高
- 在低爭(zhēng)用 低耗電的環(huán)境下 CAS效率更高
- synchronized 到重量級(jí)之后 進(jìn)入隊(duì)列 (不消耗CPU)
- CAS 等待期間消耗CPU
