Java多線(xiàn)程——ReentrantLock源碼閱讀

上一章《AQS源碼閱讀》講了AQS框架肥缔,這次講講它的應(yīng)用類(lèi)(注意不是子類(lèi)實(shí)現(xiàn)丛版,待會(huì)細(xì)講)巩掺。
ReentrantLock,顧名思義重入鎖页畦,但什么是重入胖替,這個(gè)鎖到底是怎樣的,我們來(lái)看看類(lèi)的注解說(shuō)明


ReentrantLock與隱式鎖synchronized功能相同豫缨,但ReentrantLock更具有擴(kuò)展性独令。
《鎖優(yōu)化》里提到Java在1.6對(duì)隱式鎖synchronized做了鎖的優(yōu)化,使其性能與顯式鎖性能相差無(wú)異好芭。所以在兩者的選擇上燃箭,更多的是考慮用法,以及功能上的擴(kuò)展栓撞。

ReentrantLock是線(xiàn)程獨(dú)占的遍膜,不能與其他線(xiàn)程共享。所謂的重入瓤湘,就是當(dāng)本線(xiàn)程想再次獲得鎖瓢颅,不需要重新申請(qǐng),它本身就已經(jīng)鎖了弛说,即重入該鎖挽懦。
為什么會(huì)允許鎖重入呢?因?yàn)樵摼€(xiàn)程已經(jīng)擁有鎖了木人,不會(huì)受其他線(xiàn)程干擾信柿,那么里面的共享變量就不會(huì)因?yàn)槎嗑€(xiàn)程執(zhí)行造成線(xiàn)程不安全。相當(dāng)于代碼已經(jīng)在串行執(zhí)行了醒第,沒(méi)必要再申請(qǐng)多余的鎖了渔嚷,而是重入當(dāng)前的鎖。

ReentrantLock會(huì)提供一個(gè)公平鎖的模式稠曼,如果選擇這個(gè)模式形病,會(huì)盡量使得獲取鎖是公平的,先來(lái)先得,但不一定嚴(yán)格按順序漠吻。
如果選擇了公平鎖量瓜,性能上會(huì)比不使用(默認(rèn))低一些。沒(méi)有一定保證順序途乃,同時(shí)也降性能绍傲,所以如果沒(méi)有特別的要求,盡量使用默認(rèn)的非公平鎖耍共。
現(xiàn)在基于以上的認(rèn)識(shí)烫饼,來(lái)看看ReentrantLock的基本實(shí)現(xiàn)吧。

ReentrantLock概覽

ReentrantLock是實(shí)現(xiàn)Lock接口的划提。所以主要的方法就是Lock接口定義的方法枫弟,包括lock()、tryLock()鹏往、unlock()淡诗、newCondition()等。
lock()與tryLock()的區(qū)別就是前者會(huì)一直等到直到獲取鎖伊履,后者則是嘗試在當(dāng)時(shí)獲取鎖韩容,不會(huì)重復(fù)去申請(qǐng)獲取。
這個(gè)newCondition()感覺(jué)比較突兀唐瀑,看起來(lái)完全不了解有什么用群凶,和Lock有什么關(guān)系,我們后面再詳細(xì)了解哄辣。



ReentrantLock里面有一個(gè)最核心的成員變量请梢,sync。sync的類(lèi)型就是內(nèi)部類(lèi)Sync力穗。它是AQS的子類(lèi)毅弧,也就是說(shuō)它就是實(shí)現(xiàn)ReentrantLock同步的工具。而FairSync和unFairSync則是Sync的子類(lèi)当窗,封裝了是否公平的功能够坐,用于賦值給sync成員變量。


Sync同步器

Sync是繼承上文所介紹的AQS崖面,是ReentrantLock里面的NonfairSync和FairSync的父類(lèi)元咙。
看注解可以知道,Sync用了AQS的state(狀態(tài)原子值)來(lái)標(biāo)識(shí)鎖被持有的數(shù)量巫员。


在AQS中庶香,tryRelease()是沒(méi)有定義的,所以在Sync中重寫(xiě)了简识。

先判斷下申請(qǐng)解鎖的線(xiàn)程是否獨(dú)占鎖的線(xiàn)程赶掖,否則拋出異常退出救军。
然計(jì)算新的state值,用當(dāng)前state減去releases值倘零。對(duì)于state值和releases值到底是多少,這里可以先留個(gè)懸念戳寸,但大家可以思考下上面注解的定義也可以大概猜出來(lái)呈驶。
最后判斷新state值是否為0,為0則沒(méi)有線(xiàn)程占用疫鹊,所以設(shè)當(dāng)前獨(dú)占線(xiàn)程為空袖瞻,并且更新state。這里更新state值并不需要用CAS原子操作拆吆,因?yàn)橹挥幸粋€(gè)線(xiàn)程會(huì)占用這個(gè)鎖聋迎,不是這個(gè)線(xiàn)程都異常退出了。

AQS中核心的tryAcquire()方法并沒(méi)有在這里實(shí)現(xiàn)枣耀,因?yàn)樽宇?lèi)NonfaiSync和FairSync的實(shí)現(xiàn)并不一樣霉晕。但這里同樣需要用到nonfairTryAcquire,所以抽象出來(lái)了捞奕。但為什么同樣需要牺堰,暫時(shí)不得而知,帶著問(wèn)題后面再看看颅围。
先判斷當(dāng)前鎖的state是否為0伟葫,為0則表示沒(méi)人獲取,然后通過(guò)CAS更新為acquires值(依然不知道值是多少)院促,同時(shí)更新當(dāng)前線(xiàn)程為鎖的獨(dú)占線(xiàn)程筏养。
如果state不為0,則表示有線(xiàn)程已經(jīng)占有了常拓。但可能占有的線(xiàn)程是當(dāng)前線(xiàn)程渐溶,那么當(dāng)前的state會(huì)加上acquires值。
這里很容易就看出來(lái)state就是代表重入的次數(shù)墩邀!所以上面的謎題就解開(kāi)了掌猛,releases,aquires都是代表每次申請(qǐng)的值,在ReentrantLock肯定都是1眉睹,他們的計(jì)算總值就是原子值state荔茬。
如果state不為0,也不是被當(dāng)前線(xiàn)程占用竹海,那么返回false獲取失敗慕蔚。

NonfairSync

沒(méi)啥特別的,直接調(diào)用Sync的方法斋配。也沒(méi)做修改孔飒。


FairSync

公平鎖的同步器灌闺。只有當(dāng)遞歸調(diào)用或者沒(méi)有其他等待者,再或者他自己本身排第一才能獲取鎖坏瞄。
這話(huà)比較繞口桂对,大概意思應(yīng)該是不停地輪詢(xún)申請(qǐng)鎖,直到自己排到隊(duì)列的第一才能獲取鸠匀。


乍看一看蕉斜,這個(gè)方法基本和父類(lèi)Sync的nonfairTryAcquire()一樣,唯一不同點(diǎn)就是在沒(méi)有線(xiàn)程占用的時(shí)候(state=0)缀棍,多了個(gè)!hasQueuedPredecessors()前置判斷宅此。

這個(gè)方法用來(lái)判斷是否隊(duì)列為空,或者當(dāng)前線(xiàn)程是否在隊(duì)列的最前面爬范。
所以公平鎖模式下父腕,想要能獲取鎖,除非自己排在隊(duì)列的最前面青瀑。
綜上看璧亮,F(xiàn)airSync根本沒(méi)有調(diào)用到nonfairTryAcquire(),為何說(shuō)子類(lèi)都需要用到呢斥难?繼續(xù)留著懸念杜顺,后面解答。

@ReservedStackAccess

可以看到上面介紹的tryAcquire()和tryRelease()都有@ReservedStackAccess蘸炸。這個(gè)注解到底有什么用躬络?
查找了下資料,這個(gè)是JEP 270添加的新注解搭儒。它會(huì)保護(hù)被注解的方法穷当,通過(guò)添加一些額外的空間,防止在多線(xiàn)程運(yùn)行的時(shí)候出現(xiàn)棧溢出淹禾。具體看下圖


lock()馁菜、tryLock()成員函數(shù)

ReentrantLock里面的lock()方法是調(diào)用成員變量sync的acquire()。
無(wú)論是否公平鎖都是直接調(diào)用AQS的acquire()方法铃岔,不過(guò)就是各自有tryAcuqire()的重寫(xiě)汪疮,即上文所說(shuō)的內(nèi)容。
參數(shù)1毁习,是透?jìng)鹘otryAcquire()的智嚷,所以這里代表是入鎖一次的意思。



而tryLock()調(diào)用的是成員變量sync的nonfairTryAcquire()纺且。上文說(shuō)到Sync內(nèi)部類(lèi)抽象了這個(gè)方法出來(lái)盏道,說(shuō)到子類(lèi)都會(huì)用到,說(shuō)的正是tryLock()方法需要用到载碌。
所以顯而易見(jiàn)的猜嘱,無(wú)論是否公平鎖衅枫,調(diào)用tryLock()都是用的非公平鎖的方法。為什么呢朗伶?
因?yàn)閠ryLock()的try只是嘗試弦撩,無(wú)論是否公平,對(duì)于方法來(lái)說(shuō)沒(méi)有必要论皆,只是嘗試申請(qǐng)的時(shí)候能否獲取鎖而已孤钦。



至于其他成員函數(shù),大都是圍繞獲取線(xiàn)程和隊(duì)列的狀態(tài)纯丸,沒(méi)什么特別的,在這里不再贅述静袖,有興趣的可以看看源碼觉鼻。

總結(jié)

回顧下要點(diǎn)

  1. ReentrantLock是一個(gè)可重入的鎖(被當(dāng)前占用的線(xiàn)程重入)。
  2. 它有兩種模式公平與非公平队橙,通過(guò)NonfairSync和FairSync賦值sync成員變量實(shí)現(xiàn)坠陈。
  3. 兩種模式都是AQS的子類(lèi),通過(guò)重寫(xiě)tryAcquire()區(qū)別不同捐康。公平鎖多了是否在隊(duì)列的頭的判斷仇矾。
  4. tryLock()方法沒(méi)有區(qū)分模式,都是一樣的解总。

上文提到的newCondition()還沒(méi)有涉及到贮匕,等后續(xù)再起一章節(jié)說(shuō)下這個(gè)Condition。

如果覺(jué)得還不錯(cuò)花枫,請(qǐng)關(guān)注微信公眾號(hào):Zack說(shuō)碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刻盐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子劳翰,更是在濱河造成了極大的恐慌敦锌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佳簸,死亡現(xiàn)場(chǎng)離奇詭異乙墙,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)生均,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)听想,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人马胧,你說(shuō)我怎么就攤上這事哗魂。” “怎么了漓雅?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵录别,是天一觀的道長(zhǎng)朽色。 經(jīng)常有香客問(wèn)我,道長(zhǎng)组题,這世上最難降的妖魔是什么葫男? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮崔列,結(jié)果婚禮上梢褐,老公的妹妹穿的比我還像新娘。我一直安慰自己赵讯,他們只是感情好盈咳,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著边翼,像睡著了一般鱼响。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上组底,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天丈积,我揣著相機(jī)與錄音,去河邊找鬼债鸡。 笑死江滨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的厌均。 我是一名探鬼主播唬滑,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼棺弊!你這毒婦竟也來(lái)了间雀?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镊屎,失蹤者是張志新(化名)和其女友劉穎惹挟,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體缝驳,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡连锯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了用狱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片运怖。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖夏伊,靈堂內(nèi)的尸體忽然破棺而出摇展,到底是詐尸還是另有隱情,我是刑警寧澤溺忧,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布咏连,位于F島的核電站盯孙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏祟滴。R本人自食惡果不足惜振惰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垄懂。 院中可真熱鬧骑晶,春花似錦、人聲如沸草慧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)漫谷。三九已至仔雷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抖剿,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工识窿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斩郎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓喻频,卻偏偏與公主長(zhǎng)得像缩宜,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子甥温,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容