synchronized是Java較為古老的同步實(shí)現(xiàn)方式,大家可能叫監(jiān)視器鎖,synchronized不需要顯式加鎖與解鎖,當(dāng)訪問(wèn)其修飾的方法或者同步塊時(shí),會(huì)自動(dòng)獲取鎖,從生成的Java字節(jié)碼來(lái)看,編譯器在同步塊開(kāi)始的地方插入了MONITORENTER,在結(jié)束的地方插入MONITOREXIT,這可能也是監(jiān)視器鎖這個(gè)名字的由來(lái)。
synchronized的鎖存放在每個(gè)對(duì)象的對(duì)象頭的MarkWord中,在1.6之后,又增加了偏向鎖的支持,減少同一線程獲取鎖的性能損耗。synchronized的鎖狀態(tài)分為無(wú)鎖,偏向鎖,輕量級(jí)鎖,重量級(jí)鎖四種。
MarkWord結(jié)構(gòu)(64位 jvm):

偏向鎖在同一線程獲取鎖時(shí),不需要加鎖與解鎖,只需要判斷當(dāng)前對(duì)象頭是否有當(dāng)前線程的偏向鎖,有則獲取鎖,若無(wú)則去判斷是否設(shè)置了偏向標(biāo)識(shí),有偏向標(biāo)識(shí),則CAS設(shè)置偏向鎖,無(wú)則CAS競(jìng)爭(zhēng)鎖。
偏向鎖有一個(gè)撤銷(xiāo)的過(guò)程,在一個(gè)線程獲取到偏向鎖之后,另外一個(gè)線程來(lái)競(jìng)爭(zhēng)鎖,會(huì)如下圖所示,先暫停持有偏向鎖的線程,檢查線程是否活動(dòng)(線程死了也暫停不了吧),如果還活動(dòng)就開(kāi)始升級(jí)為輕量級(jí)鎖,否則重新偏向到新的線程。

輕量級(jí)鎖在存在競(jìng)爭(zhēng)的時(shí)候又會(huì)發(fā)生鎖的膨脹,在輕量級(jí)鎖競(jìng)爭(zhēng)較激烈時(shí),比如一個(gè)線程持有鎖,另外一個(gè)線程在循環(huán)CAS(自旋)獲取鎖時(shí),再來(lái)一個(gè)線程競(jìng)爭(zhēng)鎖,這里總不能一直自旋下去,因?yàn)楸容^消耗cpu,因此就升級(jí)為重量級(jí)鎖。這時(shí)候競(jìng)爭(zhēng)鎖的行為就改變了,從自旋變成了阻塞。具體如下圖:

最后鎖只能升級(jí),不能降級(jí),因?yàn)樵诟?jìng)爭(zhēng)激烈的情況下,自旋只會(huì)讓cpu空轉(zhuǎn),啥事也沒(méi)有做。
總結(jié):偏向鎖解鎖和加鎖不需要額外的同步消耗,但是在存在競(jìng)爭(zhēng)時(shí)會(huì)存在撤銷(xiāo)和升級(jí)。(單純一個(gè)線程訪問(wèn)需要同步嗎?除非有這樣一種情況,雖然也是多個(gè)線程,但是其中一個(gè)線程多次獲取同一個(gè)對(duì)象的鎖,這個(gè)時(shí)候,可能會(huì)有一些性能提升。另外有人還建議直接使用-XX:-UseBiasedLocking=false關(guān)閉偏向鎖)
輕量級(jí)鎖用CAS,競(jìng)爭(zhēng)時(shí)不會(huì)阻塞,但是循環(huán)CAS比較消耗CPU(基本上所有的鎖(除了偏向鎖),輕量級(jí)鎖,重量級(jí)鎖,以及互斥鎖里面加鎖解鎖都是循環(huán)CAS,就不消耗CPU嗎,其中比較合理的解釋就是使用CAS是認(rèn)為這個(gè)過(guò)程比較快就可以完成,如果比較慢的時(shí)候還是直接阻塞在那吧)
重量級(jí)鎖的優(yōu)缺點(diǎn)正好和輕量級(jí)相對(duì)。
參考書(shū)籍和文檔:
1.《深入理解Java虛擬機(jī)》
2.《Java并發(fā)編程的藝術(shù)》