在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    面試官:有了解過ReentrantLock的底層實(shí)現(xiàn)嗎?說說看

    我們可以了解到它是一個(gè)可重入鎖,下面我們就一起看一下它的底層實(shí)現(xiàn)~

    構(gòu)造函數(shù)

    我們?cè)谑褂玫臅r(shí)候,都是先new它,所以我們先看下它的構(gòu)造函數(shù),它主要有兩個(gè):

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

    從字面上看,它們之間的不同點(diǎn)在于fair,翻譯過來就是公平的意思,大體可以猜到它是用來構(gòu)建公平鎖和非公平鎖,在繼續(xù)往下看源碼之前,先給大家科普一下這兩種鎖。

    公平鎖 & 非公平鎖

    • 公平鎖 多個(gè)線程按照申請(qǐng)鎖的順序去獲得鎖,線程會(huì)直接進(jìn)入隊(duì)列去排隊(duì),永遠(yuǎn)都是隊(duì)列的第一位才能得到鎖。(例如銀行辦業(yè)務(wù)取號(hào))

    這種鎖的優(yōu)點(diǎn)很明顯,每個(gè)線程都能夠獲取資源,缺點(diǎn)也很明顯,如果某個(gè)線程阻塞了,其它線程也會(huì)阻塞,然而cpu喚醒開銷很大,之前也給大家講過

    • 非公平鎖 多個(gè)線程都去嘗試獲取鎖,獲取不到就進(jìn)入等待隊(duì)列,cpu也不用去喚醒

    優(yōu)缺點(diǎn)正好和上邊相反,優(yōu)點(diǎn)減少開銷,缺點(diǎn)也很明顯,可能會(huì)導(dǎo)致一直獲取不到鎖或長時(shí)間獲取不到鎖

    好,有了基本概念之后,我們繼續(xù)往下看

    NonfairSync

    首先,我們看下非公平鎖,默認(rèn)情況下,我們申請(qǐng)的都是非公平鎖,也就是new ReentrantLock(),我們接著看源碼

    static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }}

    它繼承了Sync,Sync是一個(gè)內(nèi)容靜態(tài)抽象類:

    abstract static class Sync extends AbstractQueuedSynchronizer {…}

    分為公平和非公平,使用AQS狀態(tài)來表示持鎖的次數(shù),在構(gòu)造函數(shù)初始化的時(shí)候都有sync = …,我們接著看NonfairSync。在使用的時(shí)候,我們調(diào)用了lock.lock()方法,它是ReentrantLock的一個(gè)實(shí)例方法

    // 獲取鎖 public void lock() { sync.lock(); }

    實(shí)際上內(nèi)部還是調(diào)了sync的內(nèi)部方法,因?yàn)槲覀兩暾?qǐng)的是非公平鎖,所以我們看NonfairSync下的lock實(shí)現(xiàn):

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

    compareAndSetState這個(gè)方法,是AQS的內(nèi)部方法,意思是如果當(dāng)前狀態(tài)值等于預(yù)期值,則自動(dòng)將同步狀態(tài)設(shè)置為給定的更新值。此操作具有volatile讀寫的內(nèi)存語義。

    protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update);}

    可以看到執(zhí)行l(wèi)ock方法,會(huì)通過AQS機(jī)制計(jì)數(shù),setExclusiveOwnerThread設(shè)置線程獨(dú)占訪問權(quán)限,它是AbstractOwnableSynchronizer的一個(gè)內(nèi)部方法,子類通過使用它來管理線程獨(dú)占

    public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {}

    可以看到它是繼承了AbstractOwnableSynchronizer。下面接著看,我們說如果實(shí)際值等于期望值會(huì)執(zhí)行上邊的方法,不期望的時(shí)候會(huì)執(zhí)行acquire(1)

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

    這個(gè)方法以獨(dú)占模式獲取,忽略中斷,它會(huì)嘗試調(diào)用tryAcquire,成功會(huì)返回,不成功進(jìn)入線程排隊(duì),可以重復(fù)阻塞和解除阻塞??聪翧QS 內(nèi)部的這個(gè)方法

    protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException();}

    我們可以看到實(shí)現(xiàn)肯定不在這,它的具體實(shí)現(xiàn)在NonfairSync

    protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }

    可以看到它調(diào)用了,nonfairTryAcquire方法,這個(gè)方法是不公平的tryLock,具體實(shí)現(xiàn)在Sync內(nèi)部,這里我們要重點(diǎn)關(guān)注一下

    final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); // 返回同步狀態(tài)值,它是AQS內(nèi)部的一個(gè)方法 // private volatile int state; // protected final int getState() { // return state; // } int c = getState(); if (c == 0) { // 為0就比較一下,如果與期望值相同就設(shè)置為獨(dú)占線程,說明鎖已經(jīng)拿到了 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 否則 判斷如果當(dāng)前線程已經(jīng)是被設(shè)置獨(dú)占線程了 else if (current == getExclusiveOwnerThread()) { // 設(shè)置當(dāng)前線程狀態(tài)值 + 1 并返回成功 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } // 否則返回失敗 沒拿到鎖 return false;}

    好,我們?cè)倩剡^頭看下 acquire

    public final void acquire(int arg) { // 如果當(dāng)前線程沒有獲取到鎖 并且 在隊(duì)列中的線程嘗試不斷拿鎖如果被打斷了會(huì)返回true, 就會(huì)調(diào)用 selfInterrupt if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }

    selfInterrupt很好理解,線程中斷

    static void selfInterrupt() { Thread.currentThread().interrupt(); }

    其實(shí)我們關(guān)注的重點(diǎn)是這個(gè)方法acquireQueued,首先關(guān)注一下入?yún)?它內(nèi)部傳入了一個(gè)addWaiter,最后它回NODE節(jié)點(diǎn)

    private Node addWaiter(Node mode) { // mode 沒啥好說的就是一個(gè)標(biāo)記,用于標(biāo)記獨(dú)占模式 static final Node EXCLUSIVE = null; Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; }

    我們可以大體從猜到,Node是一個(gè)等待隊(duì)列的節(jié)點(diǎn)類,是一個(gè)鏈表結(jié)構(gòu),之前我們講FutureTask源碼的時(shí)候也遇到過這種結(jié)構(gòu),它通常用于自旋鎖,在這個(gè)地方,它是用于阻塞同步器

    +——+ prev +—–+ +—–+head | | <—- | | <—- | | tail +——+ +—–+ +—–+

    好,下面我們關(guān)注一下 acquireQueued

    final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { // 默認(rèn)是 false boolean interrupted = false; // 進(jìn)入阻塞循環(huán)遍歷 線程隊(duì)列 for (;;) { // 返回前一個(gè)節(jié)點(diǎn) final Node p = node.predecessor(); // 判斷如果前一個(gè)節(jié)點(diǎn)是頭部節(jié)點(diǎn),并且拿到鎖了,就會(huì)設(shè)置當(dāng)前節(jié)點(diǎn)為頭部節(jié)點(diǎn) if (p == head && tryAcquire(arg)) { setHead(node); // 這里可以看到注釋 help gc , p.next = null; // help GC failed = false; return interrupted; } // 檢查并更新未能獲取的節(jié)點(diǎn)的狀態(tài)。如果線程應(yīng)該阻塞,則返回 true 并且線程中斷了 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { // 如果失敗 取消正在嘗試獲取的節(jié)點(diǎn) if (failed) cancelAcquire(node); }}

    從上面的源碼來看,在體會(huì)一下上面講的非公平鎖的概念,是不是更好理解一些,然后就是釋放鎖unlock,這個(gè)方法我們可以看到是ReentrantLock下的一個(gè)實(shí)例方法,所以公平鎖的釋放鎖也是調(diào)的這個(gè)方法,其實(shí)最終可以猜到調(diào)用的還是sync的方法

    public void unlock() { sync.release(1); }

    Sync繼承AQS,release是AQS的內(nèi)部方法

    public final boolean release(int arg) { // 嘗試釋放鎖 tryRelease 在Sync內(nèi)部 if (tryRelease(arg)) { Node h = head; // 如果節(jié)點(diǎn)存在 并且狀態(tài)值不為0 if (h != null && h.waitStatus != 0) // 喚醒下個(gè)節(jié)點(diǎn) unparkSuccessor(h); return true; } return false; }private void unparkSuccessor(Node node) { int ws = node.waitStatus; if (ws 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) // 可以看到調(diào)用了 LockSupport來喚醒 LockSupport.unpark(s.thread); }

    我們?cè)倏聪聇ryRelease, 同樣這個(gè)實(shí)現(xiàn)在Sync內(nèi)

    protected final boolean tryRelease(int releases) { // 同樣釋放鎖的時(shí)候 依然使用 AQS計(jì)數(shù) int c = getState() – releases; // 判斷當(dāng)前線程是否是獨(dú)占線程,不是拋出異常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; // 如果是0 表示是釋放成功 if (c == 0) { free = true; // 并且把獨(dú)占線程設(shè)為null setExclusiveOwnerThread(null); } // 更新狀態(tài)值 setState(c); return free; }

    FairSync

    公平鎖FairSync的區(qū)別在于,它的獲取鎖的實(shí)現(xiàn)在它的內(nèi)部,Sync默認(rèn)內(nèi)部實(shí)現(xiàn)了非公平鎖

    static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; // 這個(gè)方法最終調(diào)用 tryAcquire final void lock() { acquire(1); } // 公平鎖的實(shí)現(xiàn) protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // 這邊和非公平鎖的實(shí)現(xiàn)有些相似 同樣判斷狀態(tài) if (c == 0) { // 判斷排隊(duì)隊(duì)列是否存在, 不存在并且比較期望值 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { // 設(shè)置獨(dú)占線程 并返回成功 setExclusiveOwnerThread(current); return true; } } // 這邊和上面類似 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }

    它的實(shí)現(xiàn)比較簡單,通過實(shí)現(xiàn)可以發(fā)現(xiàn),它按照申請(qǐng)鎖的順序來獲取鎖,排第一的先拿到鎖,在結(jié)合上面的概念理解一下,就很好理解了.

    釋放鎖unlock,上面我們已經(jīng)講過了~

    結(jié)束語

    本節(jié)內(nèi)容可能有點(diǎn)多,主要是看源碼,可以打斷點(diǎn)自己調(diào)一下, 舉一反三,通過源碼去理解一下什么是公平鎖和非公平鎖, ReentrantLock可重入鎖體驗(yàn)在哪里。

    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
    用戶投稿
    上一篇 2022年6月19日 15:13
    下一篇 2022年6月19日 15:13

    相關(guān)推薦

    • 分享4條發(fā)微商朋友圈的方法(微商朋友圈應(yīng)該怎么發(fā))

      對(duì)于微商朋友來說,朋友圈的重要性不言而喻了。 那么微商的朋友圈到底該怎么發(fā)呢? 為什么同樣是經(jīng)營一個(gè)朋友圈,有的微商看起來逼格滿滿,實(shí)際效果也不錯(cuò);而有的卻動(dòng)都不動(dòng)就被屏蔽甚至拉黑…

      2022年11月27日
    • 存儲(chǔ)過程語法(sql server存儲(chǔ)過程語法)

      今天小編給各位分享存儲(chǔ)過程語法的知識(shí),其中也會(huì)對(duì)sql server存儲(chǔ)過程語法進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧! oracle存儲(chǔ)過程基本語法…

      2022年11月26日
    • 《寶可夢(mèng)朱紫》夢(mèng)特性怎么獲得?隱藏特性獲取方法推薦

      寶可夢(mèng)朱紫里有很多寶可夢(mèng)都是擁有夢(mèng)特性會(huì)變強(qiáng)的寶可夢(mèng),很多玩家不知道夢(mèng)特性怎么獲得,下面就給大家?guī)韺毧蓧?mèng)朱紫隱藏特性獲取方法推薦,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 …

      2022年11月25日
    • 《寶可夢(mèng)朱紫》奇魯莉安怎么進(jìn)化?奇魯莉安進(jìn)化方法分享

      寶可夢(mèng)朱紫中的奇魯莉安要怎么進(jìn)化呢?很多玩家都不知道,下面就給大家?guī)韺毧蓧?mèng)朱紫奇魯莉安進(jìn)化方法分享,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 奇魯莉安進(jìn)化方法分享 奇魯莉安…

      2022年11月25日
    • cpu性能天梯圖2022 AMD CPU天梯圖最新排行榜出爐

      用戶在DIY自己的主機(jī)時(shí)選擇CPU是非常關(guān)鍵的,CPU可以說是電腦的大腦,大家也都想追求好一點(diǎn)的CPU來使用,但型號(hào)太多了,大部分的用戶都不知道目前哪一款CPU比較好用,快來看看詳…

      2022年11月24日
    • 《寶可夢(mèng)朱紫》暴飛龍?jiān)趺醋ィ勘╋w龍獲得方法

      寶可夢(mèng)朱紫暴飛龍位置在哪?在游戲中,很多玩家還不清楚暴飛龍具體要怎么樣獲得,其實(shí)獲得方法很簡單,暴飛龍直接是沒得抓的,需要玩家從寶貝龍進(jìn)化得到,下面一起來看一下寶可夢(mèng)朱紫暴飛龍獲得…

      2022年11月23日
    • 《寶可夢(mèng)朱紫》布土撥怎么進(jìn)化?布土撥進(jìn)化方法介紹

      寶可夢(mèng)朱紫中,不同的寶可夢(mèng)有不同的進(jìn)化方法,其中布土撥的進(jìn)化方法是比較特殊的。很多玩家不知道寶可夢(mèng)朱紫布土撥怎么進(jìn)化,下面就帶來寶可夢(mèng)朱紫布土撥進(jìn)化方法介紹,一起來看看吧,希望能幫…

      2022年11月23日
    • 《寶可夢(mèng)朱紫》薄荷怎么獲得?薄荷獲得方法

      寶可夢(mèng)朱紫中薄荷有改變寶可夢(mèng)的屬性或性格等效果,很多玩家想知道寶可夢(mèng)朱紫薄荷怎么獲得,下面就帶來寶可夢(mèng)朱紫薄荷獲得方法,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 薄荷獲得方法…

      2022年11月23日
    • 《寶可夢(mèng)朱紫》怎么交換精靈?交換精靈方法一覽

      寶可夢(mèng)朱紫中玩家可以和好友或者npc進(jìn)行交換寶可夢(mèng)獲得自己沒有的寶可夢(mèng),很多玩家想知道寶可夢(mèng)朱紫怎么交換精靈,下面就帶來寶可夢(mèng)朱紫交換精靈方法一覽,感興趣的小伙伴不要錯(cuò)過,希望能幫…

      2022年11月23日
    • 《寶可夢(mèng)朱紫》龍爪技能怎么獲得?龍爪技能獲取方法

      寶可夢(mèng)朱紫龍爪技能怎么獲得?在游戲中,很多玩家還不清楚龍爪技能應(yīng)該怎么獲取,其實(shí)獲取方法有很多,下面一起來看一下寶可夢(mèng)朱紫龍爪技能獲取方法,希望可以幫助各位玩家順利的進(jìn)行游戲內(nèi)容?!?/p>

      2022年11月23日

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息