亚洲精品中文免费|亚洲日韩中文字幕制服|久久精品亚洲免费|一本之道久久免费

      
      

            <dl id="hur0q"><div id="hur0q"></div></dl>

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

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

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

                我們在使用的時候,都是先new它,所以我們先看下它的構(gòu)造函數(shù),它主要有兩個:

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

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

                公平鎖 & 非公平鎖

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

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

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

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

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

                NonfairSync

                首先,我們看下非公平鎖,默認(rèn)情況下,我們申請的都是非公平鎖,也就是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是一個內(nèi)容靜態(tài)抽象類:

                abstract static class Sync extends AbstractQueuedSynchronizer {…}

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

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

                實際上內(nèi)部還是調(diào)了sync的內(nèi)部方法,因為我們申請的是非公平鎖,所以我們看NonfairSync下的lock實現(xiàn):

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

                compareAndSetState這個方法,是AQS的內(nèi)部方法,意思是如果當(dāng)前狀態(tài)值等于預(yù)期值,則自動將同步狀態(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方法,會通過AQS機(jī)制計數(shù),setExclusiveOwnerThread設(shè)置線程獨占訪問權(quán)限,它是AbstractOwnableSynchronizer的一個內(nèi)部方法,子類通過使用它來管理線程獨占

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

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

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

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

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

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

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

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

                final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); // 返回同步狀態(tài)值,它是AQS內(nèi)部的一個方法 // private volatile int state; // protected final int getState() { // return state; // } int c = getState(); if (c == 0) { // 為0就比較一下,如果與期望值相同就設(shè)置為獨占線程,說明鎖已經(jīng)拿到了 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 否則 判斷如果當(dāng)前線程已經(jīng)是被設(shè)置獨占線程了 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;}

                好,我們再回過頭看下 acquire

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

                selfInterrupt很好理解,線程中斷

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

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

                private Node addWaiter(Node mode) { // mode 沒啥好說的就是一個標(biāo)記,用于標(biāo)記獨占模式 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是一個等待隊列的節(jié)點類,是一個鏈表結(jié)構(gòu),之前我們講FutureTask源碼的時候也遇到過這種結(jié)構(gòu),它通常用于自旋鎖,在這個地方,它是用于阻塞同步器

                +——+ 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)遍歷 線程隊列 for (;;) { // 返回前一個節(jié)點 final Node p = node.predecessor(); // 判斷如果前一個節(jié)點是頭部節(jié)點,并且拿到鎖了,就會設(shè)置當(dāng)前節(jié)點為頭部節(jié)點 if (p == head && tryAcquire(arg)) { setHead(node); // 這里可以看到注釋 help gc , p.next = null; // help GC failed = false; return interrupted; } // 檢查并更新未能獲取的節(jié)點的狀態(tài)。如果線程應(yīng)該阻塞,則返回 true 并且線程中斷了 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { // 如果失敗 取消正在嘗試獲取的節(jié)點 if (failed) cancelAcquire(node); }}

                從上面的源碼來看,在體會一下上面講的非公平鎖的概念,是不是更好理解一些,然后就是釋放鎖unlock,這個方法我們可以看到是ReentrantLock下的一個實例方法,所以公平鎖的釋放鎖也是調(diào)的這個方法,其實最終可以猜到調(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é)點存在 并且狀態(tài)值不為0 if (h != null && h.waitStatus != 0) // 喚醒下個節(jié)點 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); }

                我們再看下tryRelease, 同樣這個實現(xiàn)在Sync內(nèi)

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

                FairSync

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

                static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; // 這個方法最終調(diào)用 tryAcquire final void lock() { acquire(1); } // 公平鎖的實現(xiàn) protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // 這邊和非公平鎖的實現(xiàn)有些相似 同樣判斷狀態(tài) if (c == 0) { // 判斷排隊隊列是否存在, 不存在并且比較期望值 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { // 設(shè)置獨占線程 并返回成功 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; } }

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

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

                結(jié)束語

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

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

                相關(guān)推薦

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

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

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

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

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

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

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

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

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

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

                  2022年11月24日
                • 《寶可夢朱紫》暴飛龍怎么抓?暴飛龍獲得方法

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

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

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

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

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

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

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

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

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

                  2022年11月23日

                聯(lián)系我們

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