ReentrantLock總結(jié)

簡(jiǎn)述

ReentrantLock是java中非常重要的一個(gè)并發(fā)工具,相比于java原生的synchronized有著更好的性能

## 概念速查
ReentrantLock涉及的名稱(chēng)和概念較多,這里做一個(gè)簡(jiǎn)單的歸類(lèi)和解釋?zhuān)唧w更為詳細(xì)的內(nèi)容,請(qǐng)自行Baidu或Google,這部分用于在閱讀文章的時(shí)候,快速了解一些名稱(chēng)的概念,如果已經(jīng)熟悉,請(qǐng)?zhí)^(guò)。

快速預(yù)覽

更強(qiáng)大的功能,玩玩意味著更為復(fù)雜的使用,ReentrankLock的使用比起synchronize,多了一個(gè)主動(dòng)釋放鎖的代碼,一個(gè)典型的使用示例如下

ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    // ... method body
}finally {
    lock.unlock();
}

注意unlock的操作一定要置于finally塊中,這樣才能保證鎖一定能釋放。

uml圖

看完了簡(jiǎn)單的使用示例,我們來(lái)快速的看一遍ReentrankLock的結(jié)構(gòu),下面是用idea的工具快速生成的uml圖,感謝idea,大大提高了我們的工作質(zhì)量。


ReentrantLock-UML.png

一次性過(guò)于深入的討論,往往會(huì)迷失在繁瑣的細(xì)節(jié)中,而難以把握全貌,而細(xì)節(jié)往往是由全局的目標(biāo)決定的,所以我們一層一層的談,不一次性深入最終代碼。

由uml圖,我們可以看出,ReentrantLock類(lèi)是一個(gè)Lock接口的具體實(shí)現(xiàn),每個(gè)ReentrantLock的實(shí)例,都持有一個(gè)sync對(duì)象,且這個(gè)sync是final修飾的,這個(gè)sync有兩種具體的子類(lèi),分別是NonfairSync和FairSync,也就是非公平鎖和公平鎖。

ReentrantLock有兩個(gè)構(gòu)造方法,我們可以先看這兩個(gè)方法,

public ReentrantLock() {
    sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
    sync = (fair)? new FairSync() : new NonfairSync();
}

可以看出,所謂構(gòu)造函數(shù),其實(shí)就是初始化需要使用的sync的類(lèi)型,默認(rèn)是非公平鎖。參考公平鎖與非公平鎖

簡(jiǎn)要的預(yù)備知識(shí)

CAS

ReentrantLock的核心是對(duì)CAS方法的使用,現(xiàn)代的CPU提供了特殊的指令,可以自動(dòng)更新共享數(shù)據(jù),而且能夠檢測(cè)到其他線(xiàn)程的干擾,而 compareAndSet()使用了這些命令,具體請(qǐng)查閱CAS原理分析

wait

第一層解析

加鎖部分

ReentrantLock的lock其實(shí)就是調(diào)用具體的sync的lock方法。
公平鎖和非公平鎖的加鎖是有所不同的
對(duì)于公平鎖來(lái)說(shuō)如下

final void lock() {
    acquire(1);
}

對(duì)于非公平鎖來(lái)說(shuō),是如下的

final void lock() {
  if (compareAndSetState(0, 1))
         setExclusiveOwnerThread(Thread.currentThread()); 
  else        acquire(1);
}

很顯然,我們可以看出對(duì)于公平鎖來(lái)說(shuō),非公平鎖多了一個(gè)操作。我們首先來(lái)解釋一下compareAndSetState方法,這個(gè)方法來(lái)自于sync繼承的AbstractQueuedSynchronizer父類(lèi)。state為0表示當(dāng)前鎖沒(méi)有被占用,如果大于0,則表示被持有了,使用compareAndSetState,底層是個(gè)CAS方法,如果鎖沒(méi)有被占用,則置為占用狀態(tài),并且通過(guò)setExclusiveOwnerThread,將當(dāng)前線(xiàn)程設(shè)置為該鎖的持有者。

tryAcquire這個(gè)方法的作用,java的官方注釋上如下寫(xiě)到
Acquires in exclusive mode, ignoring interrupts
大意是"嘗試在獨(dú)占模式下獲取,忽略中斷"。
截止到目前為止,我們看到的加鎖過(guò)程的流程圖如下,很簡(jiǎn)單

ReentrantLock第一層.png
acquire的工作

接下來(lái),我們研究一下acquire做的工作

public final void acquire(int arg) {
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

tryAcquire,嘗試將鎖的狀態(tài)置為arg,如果成功,則結(jié)束function,如果失敗,在CHL隊(duì)列中添加一個(gè)新的獨(dú)占鎖的節(jié)點(diǎn),節(jié)點(diǎn)如果添加失敗,則不做后續(xù)處理,如果成功則使用selfInterrupt將當(dāng)前線(xiàn)程中斷。流程圖如下

解鎖部分

我們跳過(guò)acquire具體做了什么,我們直接來(lái)看unlock做了什么。

public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;        
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;    
    }    
    return false;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作者: 一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-03】 更新日志 前言 在java中,鎖是實(shí)現(xiàn)并發(fā)的關(guān)鍵組件,多個(gè)...
    一字馬胡閱讀 44,324評(píng)論 1 32
  • 前言 上一篇文章《基于CAS操作的Java非阻塞同步機(jī)制》 分析了非同步阻塞機(jī)制的實(shí)現(xiàn)原理,本篇將分析一種以非同步...
    Mars_M閱讀 4,922評(píng)論 5 9
  • 博客鏈接:http://www.ideabuffer.cn/2017/03/15/深入理解AbstractQueu...
    閃電是只貓閱讀 6,331評(píng)論 5 22
  • 孤獨(dú) 衍生出漠視 漠視 助長(zhǎng)了孤獨(dú) 被抽空的世界 生怕誰(shuí)闖進(jìn)來(lái) 溫暖了你 于是關(guān)上門(mén)
    尚曉閱讀 244評(píng)論 1 3
  • 月已懸掛鉤上樓臺(tái),春風(fēng)對(duì)面吹夜已白。 舟似沉側(cè)畔遙江面,兩點(diǎn)雪飄飛奈何來(lái)。 情字寒凄切對(duì)長(zhǎng)晚,思念如海水奔月懷。 ...
    昨夜星辰已泛黃閱讀 239評(píng)論 0 2

友情鏈接更多精彩內(nèi)容