每個(gè)Java對(duì)象都可以用做一個(gè)實(shí)現(xiàn)同步的鎖,這些鎖被稱為內(nèi)置鎖或監(jiān)視器鎖弥激。線程在進(jìn)入同步代碼塊之前會(huì)自動(dòng)獲取鎖进陡,并且在退出同步代碼塊時(shí)會(huì)自動(dòng)釋放鎖。獲得內(nèi)置鎖的唯一途徑就是進(jìn)入由這個(gè)鎖保護(hù)的同步代碼塊或方法微服。
當(dāng)某個(gè)線程請(qǐng)求一個(gè)由其他線程持有的鎖時(shí)趾疚,發(fā)出請(qǐng)求的線程就會(huì)阻塞。然而以蕴,由于內(nèi)置鎖是可重入的糙麦,因此如果摸個(gè)線程試圖獲得一個(gè)已經(jīng)由它自己持有的鎖,那么這個(gè)請(qǐng)求就會(huì)成功丛肮∩陌酰“重入”意味著獲取鎖的操作的粒度是“線程”,而不是調(diào)用宝与。重入的一種實(shí)現(xiàn)方法是焚廊,為每個(gè)鎖關(guān)聯(lián)一個(gè)獲取計(jì)數(shù)值和一個(gè)所有者線程。當(dāng)計(jì)數(shù)值為0時(shí)伴鳖,這個(gè)鎖就被認(rèn)為是沒(méi)有被任何線程所持有节值,當(dāng)線程請(qǐng)求一個(gè)未被持有的鎖時(shí),JVM將記下鎖的持有者榜聂,并且將獲取計(jì)數(shù)值置為1搞疗,如果同一個(gè)線程再次獲取這個(gè)鎖,計(jì)數(shù)值將遞增,而當(dāng)線程退出同步代碼塊時(shí)匿乃,計(jì)數(shù)器會(huì)相應(yīng)地遞減桩皿。當(dāng)計(jì)數(shù)值為0時(shí),這個(gè)鎖將被釋放幢炸。
重入進(jìn)一步提升了加鎖行為的封裝性泄隔,因此簡(jiǎn)化了面向?qū)ο蟛l(fā)代碼的開(kāi)發(fā)。分析如下程序:
子類覆寫(xiě)了父類的同步方法宛徊,然后調(diào)用父類中的方法佛嬉,此時(shí)如果沒(méi)有可重入的鎖,那么這段代碼件產(chǎn)生死鎖闸天。
由于Fither和Child中的doSomething方法都是synchronized方法暖呕,因此每個(gè)doSomething方法在執(zhí)行前都會(huì)獲取Child對(duì)象實(shí)例上的鎖。如果內(nèi)置鎖不是可重入的苞氮,那么在調(diào)用super.doSomething時(shí)將無(wú)法獲得該Child對(duì)象上的互斥鎖湾揽,因?yàn)檫@個(gè)鎖已經(jīng)被持有,從而線程會(huì)永遠(yuǎn)阻塞下去笼吟,一直在等待一個(gè)永遠(yuǎn)也無(wú)法獲取的鎖库物。重入則避免了這種死鎖情況的發(fā)生。
同一個(gè)線程在調(diào)用本類中其他synchronized方法/塊或父類中的synchronized方法/塊時(shí)贷帮,都不會(huì)阻礙該線程地執(zhí)行戚揭,因?yàn)榛コ怄i時(shí)可重入的。