成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java多線程—ReentrantReadWriteLock源碼閱讀

Ververica / 1934人閱讀

摘要:不同的是它還多了內(nèi)部類和內(nèi)部類,以及讀寫對(duì)應(yīng)的成員變量和方法。另外是給和內(nèi)部類使用的。內(nèi)部類前面說(shuō)到的操作是分配到里面執(zhí)行的。他們都是接口的實(shí)現(xiàn),所以其實(shí)最像應(yīng)該是這個(gè)兩個(gè)內(nèi)部類。而且大體上也沒(méi)什么差異,也是用的內(nèi)部類。

之前講了《AQS源碼閱讀》和《ReentrantLock源碼閱讀》,本次將延續(xù)閱讀下ReentrantReadWriteLock,建議沒(méi)看過(guò)之前兩篇文章的,先大概了解下,有些內(nèi)容會(huì)基于之前的基礎(chǔ)上閱讀。
這個(gè)并不是ReentrantLock簡(jiǎn)單的升級(jí),而是落地場(chǎng)景的優(yōu)化,我們來(lái)詳細(xì)了解下吧。

背景

JUC包里面已經(jīng)有一個(gè)ReentrantLock了,為何還需要一個(gè)ReentrantReadWriteLock呢?看看頭注解找點(diǎn)線索。

它是ReadWriteLock接口的實(shí)現(xiàn)。那看看這個(gè)接口怎么說(shuō)

在實(shí)際場(chǎng)景中,一般來(lái)說(shuō),讀數(shù)據(jù)遠(yuǎn)比寫數(shù)據(jù)要多。如果我們還是用獨(dú)占鎖去鎖線程避免線程不安全的話,是非常低效的,而且同時(shí)也會(huì)失去它的并發(fā)性。多線程也沒(méi)有意義了。所以ReadWriteLock就是解決這個(gè)問(wèn)題所存在的。

看回ReentrantReadWriteLock的頭注解。

ReentrantReadWriteLock依然有公平鎖/非公平鎖的功能,與ReentrantLock不同在于,前者內(nèi)部維護(hù)了讀鎖和寫鎖,在公平/非公平模式下,他們會(huì)一起去競(jìng)爭(zhēng)這個(gè)鎖資源。

上圖是兩條ReentrantReadWriteLock最核心的規(guī)則。

申請(qǐng)讀鎖。當(dāng)沒(méi)有其他寫鎖占有,或者讀鎖在隊(duì)列中排隊(duì)時(shí)間最長(zhǎng)的,才能成功

申請(qǐng)寫鎖。當(dāng)沒(méi)有其他線程占有讀/寫鎖的情況下,才能成功

又以上兩條規(guī)則可以推導(dǎo)出,

寫鎖比讀鎖要高級(jí)

有讀鎖占用可以繼續(xù)申請(qǐng)讀鎖,但其他線程不能申請(qǐng)寫鎖

有寫鎖占用其他線程讀寫都不能申請(qǐng)

所以扣ReadWriteLock接口的說(shuō)明,可以讓讀并發(fā),寫?yīng)氄迹岣吡顺绦虻牟l(fā)性。

ReentrantReadWriteLock構(gòu)成

看下ReentrantReadWriteLock的file struture

之前看過(guò)ReentrantLock源碼的同學(xué)肯定很熟悉這個(gè)結(jié)構(gòu),看起來(lái)相同的都是Sync同步器(AQS的子類),以及它的兩個(gè)公平/非公平子類。

不同的是它還多了ReadLock內(nèi)部類和WriteLock內(nèi)部類,以及讀寫對(duì)應(yīng)的成員變量和方法。并且少了lock()、unlock()等方法,而是把加鎖解鎖的功能下方給這兩個(gè)子類,符合ReadWriteLock接口的定義。

Sync內(nèi)部類

雖然ReentrantReadWriteLock和ReentrantLock都有Sync,但其實(shí)Sync方法已經(jīng)很大不同了,看下Sync的結(jié)構(gòu)

對(duì)比之前ReentrantLock的Sync,最大不同在于它多了**shared()方法,用于共享鎖的獲取與釋放。
另外tryReadLock()、tryWriteLock()是給WriteLock和ReadLock內(nèi)部類使用的。

tryAcquire() 獨(dú)占鎖(寫鎖)申請(qǐng)


上文介紹重入鎖說(shuō)到state代表的是重入的次數(shù),在讀寫鎖的語(yǔ)義下,state代表的讀/寫占有(重入)的次數(shù)。c為state,w為獨(dú)占重入次數(shù)。
當(dāng)有線程占用鎖時(shí)(c!=0),如果沒(méi)有寫鎖(w==0)或者獨(dú)占線程不是當(dāng)前線程,返回false獲取失敗。鎖的重入總數(shù)超過(guò)上限會(huì)拋出異常。
這里很容易看出來(lái),如果有鎖占用的時(shí)候,如果只是讀鎖,依然可以申請(qǐng)成功。這就是讀鎖的鎖升級(jí)。
當(dāng)沒(méi)有線程占用的時(shí)候,執(zhí)行writerShouldBlock()判斷是否需要阻塞線程(子類實(shí)現(xiàn)自己的條件),不需要?jiǎng)tCAS state值,返回成功。

tryAquireShared() 共享鎖(讀鎖)申請(qǐng)


讀鎖申請(qǐng)比寫鎖申請(qǐng)要復(fù)雜,有比較多沒(méi)接觸過(guò)的成員變量,判斷的語(yǔ)句也比較多。
先看看成員變量,從他們各自的變量注解可知

firstReader,是第一個(gè)獲取讀鎖的線程

firstReaderHoldCount,是firstReader的計(jì)數(shù)器。

cachedHoldCounter,最近一個(gè)成功獲取讀鎖的線程持有數(shù)計(jì)數(shù)器。

readHolds,當(dāng)前線程重入讀鎖次數(shù)。ThreadLocal,是線程安全的HoldCounter。

先判斷是否有寫鎖占有,如果寫鎖不是當(dāng)前線程,獲取讀鎖失敗,退出方法。
注意如果寫鎖是當(dāng)前線程是可以獲取讀鎖的,因?yàn)閷戞i是獨(dú)占的,這種情況下是不會(huì)有數(shù)據(jù)與其他線程共享的問(wèn)題。

滿足子類條件,也不超過(guò)總數(shù),CAS也成功的情況下,
如果沒(méi)有讀鎖,則設(shè)firstReader為當(dāng)前線程,firstReaderHoldCount為1;
如果有讀鎖,并且也是當(dāng)前線程申請(qǐng)獲取,firstReaderHoldCount自增1;
如果有讀鎖,不是當(dāng)前線程申請(qǐng),取上一個(gè)成功的緩存計(jì)數(shù)器,如果這個(gè)計(jì)數(shù)器不是當(dāng)前線程的,則設(shè)為當(dāng)前的計(jì)數(shù)器,并且自增,返回成功。(其實(shí)就是把緩存計(jì)數(shù)器置換為當(dāng)前線程的計(jì)數(shù)器)
最后不滿足條件或者CAS失敗,執(zhí)行fullTryAcquireShared(current)返回。
至于這些數(shù)據(jù)算來(lái)干嘛,等后面看看release()怎么用。

其實(shí)這個(gè)方法就是用for循環(huán)輪詢解決CAS丟失和重入失敗的問(wèn)題,具體代碼不細(xì)過(guò)了,有興趣可以自己找源碼看看。

tryRelease() 獨(dú)占鎖(寫鎖)釋放


這里又有Condition的蹤跡了,大概可以才行到Condition時(shí)控制鎖的行為的,取消喚醒等操作。
另外鎖會(huì)同時(shí)釋放讀鎖和寫鎖。
這個(gè)方法比較好理解的,只要是當(dāng)前線程操作下,持有重入數(shù)減去釋放數(shù)為0就可以釋放了,否則失敗。

tryReleaseShared() 共享鎖(讀鎖)釋放


釋放讀鎖,對(duì)正在讀的線程不會(huì)有什么影響,但可以讓等待的寫線程去開(kāi)始獲取寫鎖。
剩余的內(nèi)容就是對(duì)tryAquireShared()計(jì)算的count數(shù)值進(jìn)行釋放(自減),如果最終自減為0則釋放讀鎖成功。

WriteLock、ReadLock內(nèi)部類

前面說(shuō)到ReentrantReadWriteLock的lock()、unlock()操作是分配到Write/ReadLock里面執(zhí)行的。
他們都是Lock接口的實(shí)現(xiàn),所以其實(shí)最像ReentrantLock應(yīng)該是這個(gè)兩個(gè)內(nèi)部類。而且大體上也沒(méi)什么差異,也是用Sync的內(nèi)部類。
WriteLock、ReadLock最大的不同就是WriteLock用的獨(dú)占模式的方法,ReadLock用的是共享模式的方法。
具體的代碼實(shí)現(xiàn)基本就是上面說(shuō)明的組成,下面介紹下ReentranReadWriteLock的使用。
ReentrantLock的時(shí)候比較簡(jiǎn)單,聲明一個(gè)變量,調(diào)用lock()方法即可。

    ReentrantLock rl = new ReentrantLock();
    rl.lock();
    rl.unlock();

但ReentranReadWriteLock并不是Lock接口的實(shí)現(xiàn),所以沒(méi)有這些方法。
有的只是writeLock()、readLock(),要先調(diào)用這個(gè)方法獲取應(yīng)對(duì)的鎖對(duì)象,再調(diào)用lock()。

     ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
     rwl.readLock().lock();
     rwl.readLock().unlock();
     rwl.writeLock().lock();
     rwl.writeLock().unlock();
總結(jié)

回顧下要點(diǎn)

讀寫鎖ReentrantReadWriteLock,是基于多讀少寫的實(shí)際場(chǎng)景,提高并發(fā)性

讀寫鎖的Sync添加了共享模式的方法

讀寫鎖內(nèi)置了兩個(gè)對(duì)象readLock、writeLock,用于實(shí)際的加鎖解鎖

寫鎖是獨(dú)占的,不允許其他鎖的申請(qǐng)

讀鎖可以并發(fā)重復(fù)申請(qǐng),當(dāng)有寫鎖的時(shí)候,會(huì)發(fā)生鎖升級(jí)

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

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77064.html

相關(guān)文章

  • Java線程進(jìn)階(十)—— J.U.C之locks框架:基于AQS的讀寫鎖(5)

    摘要:關(guān)于,最后有兩點(diǎn)規(guī)律需要注意當(dāng)?shù)牡却?duì)列隊(duì)首結(jié)點(diǎn)是共享結(jié)點(diǎn),說(shuō)明當(dāng)前寫鎖被占用,當(dāng)寫鎖釋放時(shí),會(huì)以傳播的方式喚醒頭結(jié)點(diǎn)之后緊鄰的各個(gè)共享結(jié)點(diǎn)。當(dāng)?shù)牡却?duì)列隊(duì)首結(jié)點(diǎn)是獨(dú)占結(jié)點(diǎn),說(shuō)明當(dāng)前讀鎖被使用,當(dāng)讀鎖釋放歸零后,會(huì)喚醒隊(duì)首的獨(dú)占結(jié)點(diǎn)。 showImg(https://segmentfault.com/img/remote/1460000016012293); 本文首發(fā)于一世流云的專欄:...

    dunizb 評(píng)論0 收藏0
  • Lock鎖子類了解一下

    摘要:前言回顧前面多線程三分鐘就可以入個(gè)門了源碼剖析多線程基礎(chǔ)必要知識(shí)點(diǎn)看了學(xué)習(xí)多線程事半功倍鎖機(jī)制了解一下簡(jiǎn)簡(jiǎn)單單過(guò)一遍只有光頭才能變強(qiáng)上一篇已經(jīng)將鎖的基礎(chǔ)簡(jiǎn)單地過(guò)了一遍了,因此本篇主要是講解鎖主要的兩個(gè)子類那么接下來(lái)我們就開(kāi)始吧一鎖首先我們來(lái) 前言 回顧前面: 多線程三分鐘就可以入個(gè)門了! Thread源碼剖析 多線程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)多線程事半功倍 Java鎖機(jī)制了解一下 AQ...

    時(shí)飛 評(píng)論0 收藏0
  • AQS同步組件--ReentrantLock與鎖

    摘要:性能較好是因?yàn)楸苊饬司€程進(jìn)入內(nèi)核的阻塞狀態(tài)請(qǐng)求總數(shù)同時(shí)并發(fā)執(zhí)行的線程數(shù)我們首先使用聲明一個(gè)所得實(shí)例,然后使用進(jìn)行加鎖和解鎖操作。 ReentrantLock與鎖 Synchronized和ReentrantLock異同 可重入性:兩者都具有可重入性 鎖的實(shí)現(xiàn):Synchronized是依賴jvm實(shí)現(xiàn)的,ReentrantLock是jdk實(shí)現(xiàn)的。(我們可以理解為一個(gè)是操作系統(tǒng)層面的實(shí)現(xiàn)...

    dcr309duan 評(píng)論0 收藏0
  • Java線程進(jìn)階(四)—— J.U.C之locks框架:ReentrantReadWriteLoc

    摘要:我們知道,的作用其實(shí)是對(duì)類的和的增強(qiáng),是為了讓線程在指定對(duì)象上等待,是一種線程之間進(jìn)行協(xié)調(diào)的工具。當(dāng)線程調(diào)用對(duì)象的方法時(shí),必須拿到和這個(gè)對(duì)象關(guān)聯(lián)的鎖。 showImg(https://segmentfault.com/img/remote/1460000016012566); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... 一、Reentr...

    kumfo 評(píng)論0 收藏0
  • 再次認(rèn)識(shí)ReentrantReadWriteLock讀寫鎖

    摘要:但是不管怎樣,在一個(gè)線程已經(jīng)獲取鎖后,在釋放前再次獲取鎖是一個(gè)合理的需求,而且并不生硬。那么如果考慮重入,也很簡(jiǎn)單,在加鎖時(shí)將的值累加即可,表示同一個(gè)線程重入此鎖的次數(shù),當(dāng)歸零,即表示釋放完畢。 前言 最近研究了一下juc包的源碼。在研究ReentrantReadWriteLock讀寫鎖的時(shí)候,對(duì)于其中一些細(xì)節(jié)的思考和處理以及關(guān)于提升效率的設(shè)計(jì)感到折服,難以遏制想要分享這份心得的念頭,...

    miya 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<