在 Java 中 synchronized 和 ReentrantLock 默認(rèn)使用的都是非公平鎖,而它們采用非公平鎖的原因都是一致的秦忿,都是為了提升程序的性能麦射。那為什么非公平鎖就能提升性能呢?接下來(lái)我們一起來(lái)看灯谣。
非公平鎖
非公平鎖:每個(gè)線程獲取鎖的順序是隨機(jī)的潜秋,并不會(huì)遵循先來(lái)先得的規(guī)則,任何線程在某時(shí)刻都有可能直接獲取并擁有鎖胎许。
這就好比磊哥去加油峻呛,到了加油站之后發(fā)現(xiàn)前面有人在加罗售,于是我就在車?yán)锼⑵鹆硕兑簦^(guò)了一會(huì)钩述,前面的車加完油走了寨躁,但磊哥沒注意到,還在車?yán)镉淇斓乃⒅兑粞揽薄H欢藭r(shí)加油站又來(lái)了一輛車职恳,發(fā)現(xiàn)有空閑的油槍,于是就搶先在磊哥之前把油加了谜悟。這里的油槍就是鎖话肖,沒有按照到達(dá)的先后順序得到油槍,這就是非公平鎖葡幸。
公平鎖
公平鎖:每個(gè)線程獲取鎖的順序是按照線程訪問(wèn)鎖的先后順序獲取的最筒,最前面的線程總是最先獲取到鎖。
這就好像上高速排隊(duì)過(guò)收費(fèi)站一樣蔚叨,所有的車要排隊(duì)等待通行床蜘,最先來(lái)的車最先通過(guò)收費(fèi)站。
性能對(duì)比
公平鎖和非公平鎖的性能測(cè)試結(jié)果如下蔑水,以下測(cè)試數(shù)據(jù)來(lái)自于《Java 并發(fā)編程實(shí)戰(zhàn)》:
從上述結(jié)果可以看出邢锯,使用非公平鎖的吞吐率(單位時(shí)間內(nèi)成功獲取鎖的平均速率)要比公平鎖高很多。
性能分析
以上測(cè)試數(shù)據(jù)雖然說(shuō)明了結(jié)果搀别,但并不能說(shuō)明為什么非公平鎖的性能會(huì)更高丹擎?所以,接下來(lái)歇父,我們通過(guò)分析公平鎖和非公平的執(zhí)行流程蒂培,來(lái)得到這個(gè)問(wèn)題的答案。
公平鎖執(zhí)行流程
獲取鎖時(shí)榜苫,先將線程自己添加到等待隊(duì)列的隊(duì)尾并休眠护戳,當(dāng)某線程用完鎖之后,會(huì)去喚醒等待隊(duì)列中隊(duì)首的線程嘗試去獲取鎖垂睬,鎖的使用順序也就是隊(duì)列中的先后順序媳荒,在整個(gè)過(guò)程中,線程會(huì)從運(yùn)行狀態(tài)切換到休眠狀態(tài)驹饺,再?gòu)男菝郀顟B(tài)恢復(fù)成運(yùn)行狀態(tài)钳枕,但線程每次休眠和恢復(fù)都需要從用戶態(tài)轉(zhuǎn)換成內(nèi)核態(tài),而這個(gè)狀態(tài)的轉(zhuǎn)換是比較慢的逻淌,所以公平鎖的執(zhí)行速度會(huì)比較慢么伯。
用戶態(tài) & 內(nèi)核態(tài)
用戶態(tài)(User Mode):當(dāng)進(jìn)程在執(zhí)行用戶自己的代碼時(shí),則稱其處于用戶運(yùn)行態(tài)卡儒。內(nèi)核態(tài)(Kernel Mode):當(dāng)一個(gè)任務(wù)(進(jìn)程)執(zhí)行系統(tǒng)調(diào)用而陷入內(nèi)核代碼中執(zhí)行時(shí)田柔,我們就稱進(jìn)程處于內(nèi)核運(yùn)行態(tài),此時(shí)處理器處于特權(quán)級(jí)最高的內(nèi)核代碼中執(zhí)行骨望。
為什么分內(nèi)核態(tài)和用戶態(tài)硬爆?
假設(shè)沒有內(nèi)核態(tài)和用戶態(tài)之分,程序就可以隨意讀寫硬件資源了擎鸠,比如隨意讀寫和分配內(nèi)存缀磕,這樣如果程序員一不小心將不適當(dāng)?shù)膬?nèi)容寫到了不該寫的地方,很可能就會(huì)導(dǎo)致系統(tǒng)崩潰劣光。
而有了用戶態(tài)和內(nèi)核態(tài)的區(qū)分之后袜蚕,程序在執(zhí)行某個(gè)操作時(shí)會(huì)進(jìn)行一系列的驗(yàn)證和檢驗(yàn)之后,確認(rèn)沒問(wèn)題之后才可以正常的操作資源绢涡,這樣就不會(huì)擔(dān)心一不小心就把系統(tǒng)搞壞的情況了牲剃,也就是有了內(nèi)核態(tài)和用戶態(tài)的區(qū)分之后可以讓程序更加安全的運(yùn)行,但同時(shí)兩種形態(tài)的切換會(huì)導(dǎo)致一定的性能開銷雄可。
非公平鎖執(zhí)行流程
當(dāng)線程獲取鎖時(shí)凿傅,會(huì)先通過(guò) CAS 嘗試獲取鎖,如果獲取成功就直接擁有鎖数苫,如果獲取鎖失敗才會(huì)進(jìn)入等待隊(duì)列聪舒,等待下次嘗試獲取鎖。這樣做的好處是虐急,獲取鎖不用遵循先到先得的規(guī)則箱残,從而避免了線程休眠和恢復(fù)的操作,這樣就加速了程序的執(zhí)行效率止吁。
比如前幾天磊哥去一個(gè)小營(yíng)業(yè)廳辦理網(wǎng)絡(luò)移機(jī)的業(yè)務(wù)被辑,去了之后發(fā)現(xiàn)前面有人在辦業(yè)務(wù),于是磊哥就告訴前面(辦理業(yè)務(wù))的小姐姐赏殃,“我門口休息一下敷待,您等會(huì)辦理完業(yè)務(wù),麻煩去門口叫一下我”仁热,小姐姐人也比較好榜揖,一口就答應(yīng)下來(lái)了。但在小姐姐辦完業(yè)務(wù)之后叫我抗蠢,和我回到柜臺(tái)辦理業(yè)務(wù)之間举哟,是有一段空閑時(shí)間的,這和等待隊(duì)列中的線程被喚醒和恢復(fù)執(zhí)行之間是有一段空閑時(shí)間是一樣的迅矛,而在這個(gè)空閑的時(shí)間中妨猩,營(yíng)業(yè)廳又來(lái)了一個(gè)老李頭來(lái)交話費(fèi),等老李交完話費(fèi)秽褒,我恰好也剛回來(lái)可以直接辦理業(yè)務(wù)了壶硅,這樣就是一個(gè)“三贏”的局面威兜。老李頭不用排在我后面等著繳話費(fèi),我也不用等老李頭交完話費(fèi)再辦理移機(jī)庐椒,而且在單位時(shí)間內(nèi)提高了營(yíng)業(yè)員辦理業(yè)務(wù)的效率椒舵,她也能早早的回家,這就是所謂的“三贏”约谈。在更短的時(shí)間內(nèi)執(zhí)行更多的任務(wù)次洼,這就是非公平鎖的優(yōu)勢(shì)凹蜈。
總結(jié)
本文我們介紹了公平鎖和非公平鎖的定義以及執(zhí)行流程室囊,從二者執(zhí)行流程的細(xì)節(jié)可以看出饲宿,非公平鎖因?yàn)椴挥冒矗槪┬驁?zhí)行,所以后來(lái)的鎖也可以直接嘗試獲得鎖迈勋,沒有了阻塞和恢復(fù)執(zhí)行的步驟炬灭,所以它的性能會(huì)更高。
作者:Java 中文社群
鏈接:https://juejin.cn/post/6998317686836953124
來(lái)源:掘金