欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

State實(shí)現(xiàn)鎖的原理

這篇文章主要介紹“State實(shí)現(xiàn)鎖的原理”,在日常操作中,相信很多人在State實(shí)現(xiàn)鎖的原理問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”State實(shí)現(xiàn)鎖的原理”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

目前創(chuàng)新互聯(lián)已為上千余家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬主機(jī)、網(wǎng)站托管運(yùn)營、企業(yè)網(wǎng)站設(shè)計(jì)、大冶網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

今天我們就來聊一聊基于AQS實(shí)現(xiàn)的各種鎖。

1 ReentrantLock

我們先來看一下UML類圖:

State實(shí)現(xiàn)鎖的原理

從圖中可以看到,ReentrantLock使用抽象內(nèi)部類Sync來實(shí)現(xiàn)了AQS的方法,然后基于Sync這個(gè)同步器實(shí)現(xiàn)了公平鎖和非公平鎖。主要實(shí)現(xiàn)了下面3個(gè)方法:

  • tryAcquire(int arg):獲取獨(dú)占鎖

  • tryRelease(int arg):釋放獨(dú)占鎖

  • isHeldExclusively:當(dāng)前線程是否占有獨(dú)占鎖

ReentrantLock默認(rèn)實(shí)現(xiàn)的是非公平鎖,可以在構(gòu)造函數(shù)指定。

從實(shí)現(xiàn)的方法可以看到,ReentrantLock中獲取的鎖是獨(dú)占鎖,我們再來看一下獲取和釋放獨(dú)占鎖的代碼:

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

獨(dú)占鎖的特點(diǎn)是調(diào)用上面acquire方法,傳入的參數(shù)是1。

1.1 獲取公平鎖

獲取鎖首先判斷同步狀態(tài)(state)的值。

1.1.1 state等于0

這說明沒有線程占用鎖,當(dāng)前線程如果符合下面兩個(gè)條件,就可以獲取到鎖:

  • 沒有前任節(jié)點(diǎn),如下圖:

State實(shí)現(xiàn)鎖的原理

  • CAS的方式更新state值(把0更新成1)成功。

如果獲取獨(dú)占鎖成功,會更新AQS中exclusiveOwnerThread為當(dāng)前線程,這個(gè)很容易理解。

1.1.2 state不等于0

這說明已經(jīng)有線程占有鎖,判斷占有鎖的線程是不是當(dāng)前線程,如下圖:

State實(shí)現(xiàn)鎖的原理

state += 1值如果小于0,會拋出異常。

如果獲取鎖失敗,則進(jìn)入AQS隊(duì)列等待喚醒。

1.2 獲取非公平鎖

跟公平鎖相比,非公平鎖的唯一不同是如果判斷到state等于0,不用判斷有沒有前任節(jié)點(diǎn),只要CAS設(shè)置state值(把0更新成1)成功,就獲取到了鎖。

1.3 釋放鎖

公平鎖和非公平鎖,釋放邏輯完全一樣,都是在內(nèi)部類Sync中實(shí)現(xiàn)的。釋放鎖需要注意兩點(diǎn),如下圖:

State實(shí)現(xiàn)鎖的原理

為什么state會大于1,因?yàn)槭强梢灾厝氲?,占有鎖的線程可以多次獲取鎖。

1.4 總結(jié)

公平鎖的特點(diǎn)是每個(gè)線程都要進(jìn)行排隊(duì),不用擔(dān)心線程永遠(yuǎn)獲取不到鎖,但有個(gè)缺點(diǎn)是每個(gè)線程入隊(duì)后都需要阻塞和被喚醒,這一定程度上影響了效率。非公平鎖的特點(diǎn)是每個(gè)線程入隊(duì)前都會先嘗試獲取鎖,如果獲取成功就不會入隊(duì)了,這比公平鎖效率高。但也有一個(gè)缺點(diǎn),隊(duì)列中的線程有可能等待很長時(shí)間,高并發(fā)下甚至可能永遠(yuǎn)獲取不到鎖。

2 ReentrantReadWriteLock

我們先來看一下UML類圖:

State實(shí)現(xiàn)鎖的原理

從圖中可以看到,ReentrantReadWriteLock使用抽象內(nèi)部類Sync來實(shí)現(xiàn)了AQS的方法,然后基于Sync這個(gè)同步器實(shí)現(xiàn)了公平鎖和非公平鎖。主要實(shí)現(xiàn)了下面3個(gè)方法:

  • tryAcquire(int arg):獲取獨(dú)占鎖

  • tryRelease(int arg):釋放獨(dú)占鎖

  • tryAcquireShared(int arg):獲取共享鎖

  • tryReleaseShared(int arg):釋放共享鎖

  • isHeldExclusively:當(dāng)前線程是否占有獨(dú)占鎖

可見ReentrantReadWriteLock里面同時(shí)用到了共享鎖和獨(dú)占鎖。

下圖是定義的幾個(gè)常用變量:

State實(shí)現(xiàn)鎖的原理

下面這2個(gè)方法用戶獲取共享鎖和獨(dú)占鎖的數(shù)量:

static int sharedCount(int c)    { return c >>> SHARED_SHIFT; } static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

從sharedCount可以看到,共享鎖的數(shù)量要右移16位獲取,也就是說共享鎖占了高16位。從上圖EXCLUSIVE_MASK的定義看到,跟EXCLUSIVE_MASK進(jìn)行與運(yùn)算,得到的是低16位的值,所以獨(dú)占鎖占了低16位。如下圖:

State實(shí)現(xiàn)鎖的原理

這樣上面獲取鎖數(shù)量的方法就很好理解了。參考1[1]

2.1 讀鎖

讀鎖的實(shí)現(xiàn)對應(yīng)內(nèi)部類ReadLock。

2.1.1 獲取讀鎖

獲取讀鎖實(shí)際上是ReadLock調(diào)用了AQS的下面方法,傳入?yún)?shù)是1:

public final void acquireShared(int arg) {     if (tryAcquireShared(arg) < 0)         doAcquireShared(arg); }

ReentrantReadWriteLock內(nèi)部類Sync實(shí)現(xiàn)了tryAcquireShared方法,主要包括如下三種情況:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 使用exclusiveCount方法查看state中是否有獨(dú)占鎖,如果有并且獨(dú)占線程不是當(dāng)前線程,返回-1,獲取失敗。

  3. 使用sharedCount查看state中共享鎖數(shù)量,如果讀鎖數(shù)量小于最大值(MAX_COUNT=65535),則再滿足下面3個(gè)條件就可以獲取成功并返回1:

  • 當(dāng)前線程不需要阻塞(readerShouldBlock)。在公平鎖中,需要判斷是否有前置節(jié)點(diǎn),如下圖就需要阻塞:

State實(shí)現(xiàn)鎖的原理

在非公平鎖中,則是判斷第一個(gè)節(jié)點(diǎn)是不是有獨(dú)占鎖,如下圖就需要阻塞:

State實(shí)現(xiàn)鎖的原理

  • 使用CAS把state的值加SHARED_UNIT(65536)。

這里是不是就更理解讀鎖占高位的說法了,獲取一個(gè)讀鎖,state的值就要加SHARED_UNIT這么多個(gè)。

  • 給當(dāng)前線程的holdCount加1。

如果2失敗,自旋,重復(fù)上面的步驟直到獲取到鎖。

tryAcquireShared(獲取共享鎖)會返回一個(gè)整數(shù),如下:

  • 返回負(fù)數(shù):獲取鎖失敗。

  • 返回0:獲取鎖成功但是之后再由線程來獲取共享鎖時(shí)就會失敗。

  • 返回正數(shù):獲取鎖成功而且之后再有線程來獲取共享鎖時(shí)也可能會成功。

2.1.2 釋放讀鎖

ReentrantReadWriteLock釋放讀鎖是在ReadLock中調(diào)用了AQS下面方法,傳入的參數(shù)是1:

public final boolean releaseShared(int arg) {     if (tryReleaseShared(arg)) {         doReleaseShared();         return true;     }     return false; }

ReentrantReadWriteLock內(nèi)部類Sync實(shí)現(xiàn)了releaseShared方法,具體邏輯分為下面兩步:

當(dāng)前線程holdCounter值減1。

CAS的方式將state的值減去SHARED_UNIT。

2.2 寫鎖

寫鎖的實(shí)現(xiàn)對應(yīng)內(nèi)部類WriteLock。

2.2.1 獲取寫鎖

ReentrantReadWriteLock獲取寫鎖其實(shí)是在WriteLock中調(diào)用了AQS的下面方法,傳入?yún)?shù)1:

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

在ReentrantReadWriteLock內(nèi)部類Sync實(shí)現(xiàn)了tryAcquire方法,首先獲取state值和獨(dú)占鎖數(shù)量(exclusiveCount),之后分如下兩種情況,如下圖:

State實(shí)現(xiàn)鎖的原理

state不等于0:

  • 獨(dú)占鎖數(shù)量等于0,這時(shí)說明有線程占用了共享鎖,如果當(dāng)前線程不是獨(dú)占線程,獲取鎖失敗。

  • 獨(dú)占鎖數(shù)量不等于0,獨(dú)占鎖數(shù)量加1后大于MAX_COUNT,獲取鎖失敗。

  • 上面2種情況不符合,獲取鎖成功,state值加1。

state等于0,判斷當(dāng)前線程是否需要阻塞(writerShouldBlock)。

在公平鎖中,跟readerShouldBlock的邏輯完全一樣,就是判斷隊(duì)列中head節(jié)點(diǎn)的后繼節(jié)點(diǎn)是不是當(dāng)前線程。在非公平鎖中,直接返回false,即可以直接嘗試獲取鎖。

如果當(dāng)前線程不需要阻塞,并且給state賦值成功,使用CAS方式把state值加1,把獨(dú)占線程置為當(dāng)前線程。

2.2.2 釋放寫鎖

ReentrantReadWriteLock釋放寫鎖其實(shí)是在WriteLock中調(diào)用了AQS的下面方法,傳入?yún)?shù)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; }

ReentrantReadWriteLock在Sync中實(shí)現(xiàn)了tryRelease(arg)方法,邏輯如下:

  • 判斷當(dāng)前線程是不是獨(dú)占線程,如果不是,拋出異常。

  • state值減1后,用新state值判斷獨(dú)占鎖數(shù)量是否等于0

  • 如果等于0,則把獨(dú)占線程置為空,返回true,這樣上面的代碼就可以喚醒隊(duì)列中的后置節(jié)點(diǎn)了

  • 如果不等于0,返回false,不喚醒后繼節(jié)點(diǎn)。

3 CountDownLatch

我們先來看一下UML類圖:

State實(shí)現(xiàn)鎖的原理

從上面的圖中看出,CountDownLatch的內(nèi)部類Sync實(shí)現(xiàn)了獲取共享鎖和釋放共享鎖的邏輯。

使用CountDownLatch時(shí),構(gòu)造函數(shù)會傳入一個(gè)int類型的參數(shù)count,表示調(diào)動(dòng)count次的countDown后主線程才可以被喚醒。

public CountDownLatch(int count) {     if (count < 0) throw new IllegalArgumentException("count < 0");     this.sync = new Sync(count); }

上面的Sync(count)就是將AQS中的state賦值為count。

3.1 await

CountDownLatch的await方法調(diào)用了AQS中的acquireSharedInterruptibly(int  arg),傳入?yún)?shù)1,不過這個(gè)參數(shù)并沒有用。代碼如下:

public final void acquireSharedInterruptibly(int arg)         throws InterruptedException {     if (Thread.interrupted())         throw new InterruptedException();     if (tryAcquireShared(arg) < 0)         doAcquireSharedInterruptibly(arg); }

Sync中實(shí)現(xiàn)了tryAcquireShared方法,await邏輯如下圖:

State實(shí)現(xiàn)鎖的原理

上面的自旋過程就是等待state的值不斷減小,只有state值成為0的時(shí)候,主線程才會跳出自旋執(zhí)行之后的邏輯。

3.2 countDown

CountDownLatch的countDown方法調(diào)用了AQS的releaseShared(int  arg),傳入?yún)?shù)1,不過這個(gè)參數(shù)并沒有用。內(nèi)部類Sync實(shí)現(xiàn)了tryReleaseShared方法,邏輯如下圖:

State實(shí)現(xiàn)鎖的原理

3.3 總結(jié)

CountDownLatch的構(gòu)造函數(shù)入?yún)⒅禃x值給state變量,入隊(duì)操作是主線程入隊(duì),每個(gè)子線程調(diào)用了countDown后state值減1,當(dāng)state值成為0后喚醒主線程。

4 Semaphore

Semaphore是一個(gè)信號量,用來保護(hù)共享資源。如果線程要訪問共享資源,首先從Semaphore獲取鎖(信號量),如果信號量的計(jì)數(shù)器等于0,則當(dāng)前線程進(jìn)入AQS隊(duì)列阻塞等待。否則,線程獲取鎖成功,信號量減1。使用完共享資源后,釋放鎖(信號量加1)。

Semaphore跟管程模型不一樣的是,允許多個(gè)(構(gòu)造函數(shù)的permits)線程進(jìn)入管程內(nèi)部,因此也常用它來做限流。

UML類圖如下:

State實(shí)現(xiàn)鎖的原理

Semaphore的構(gòu)造函數(shù)會傳入一個(gè)int類型參數(shù),用來初始化state的值。

4.1 acquire

獲取鎖的操作調(diào)用了AQS中的acquireSharedInterruptibly方法,傳入?yún)?shù)1,代碼見CountDownLatch中await小節(jié)。Semaphore在公平鎖和非公平鎖中分別實(shí)現(xiàn)了tryAcquireShared方法。

4.1.1 公平鎖

Semaphore默認(rèn)使用非公平鎖,如果使用公平鎖,需要在構(gòu)造函數(shù)指定。獲取公平鎖邏輯比較簡單,如下圖:

State實(shí)現(xiàn)鎖的原理

4.1.2 非公平鎖

acquire在非公平的鎖唯一的區(qū)別就是不會判斷AQS隊(duì)列是否有前置節(jié)點(diǎn)(hasQueuedPredecessors),而是直接嘗試獲取鎖。

除了acquire方法外,還有其他幾個(gè)獲取鎖的方法,原理類似,只是調(diào)用了AQS中的不同方法。

4.2 release

釋放鎖的操作調(diào)用了AQS中的releaseShared(int  arg)方法,傳入?yún)?shù)1,在內(nèi)部類Sync中實(shí)現(xiàn)了tryReleaseShared方法,邏輯很簡單:使用CAS的方式將state的值加1,之后喚醒隊(duì)列中的后繼節(jié)點(diǎn)。

5 ThreadPoolExecutor

ThreadPoolExecutor中也用到了AQS,看下面的UML類圖:

State實(shí)現(xiàn)鎖的原理

Worker主要在ThreadPoolExecutor中斷線程的時(shí)候使用。Worker自己實(shí)現(xiàn)了獨(dú)占鎖,在中斷線程時(shí)首先進(jìn)行加鎖,中斷操作后釋放鎖。按照官方說法,這里不直接使用ReentrantLock的原因是防止調(diào)用控制線程池的方法(類似setCorePoolSize)時(shí)能夠重新獲取到鎖,

5.1 tryAcquire

使用CAS的方式把AQS中state從0改為1,把當(dāng)前線程置為獨(dú)占線程。

5.2 tryRelease

把獨(dú)占線程置為空,把AQS中state改為0。

Worker初始化的時(shí)候會把state置為-1,這樣是不能獲取鎖成功的。只有調(diào)用了runWorker方法,才會通過釋放鎖操作把state更為0。這樣保證了只中斷運(yùn)行中的線程,而不會中斷等待中的線程。

到此,關(guān)于“State實(shí)現(xiàn)鎖的原理”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

名稱欄目:State實(shí)現(xiàn)鎖的原理
網(wǎng)頁鏈接:http://aaarwkj.com/article16/gdiggg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、用戶體驗(yàn)品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站營銷、品牌網(wǎng)站制作外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司
国产亚洲中文字幕无线乱码| 亚洲av优选在线观看精品| 色六月婷婷六月久久六月| 人妻熟女一区二区aⅴ在线视频 | 毛茸茸的阴户在线观看| 在线观看91高清视频| 国产91对白在线观看| av资源网大全手机在线观看| 熟妇人妻精品视频一区二区| 欧美香蕉一区二区视频| 亚洲精品国产av成人网| 韩日av一区二区三区| 中文成人无字幕乱码精品| 国产成人免费公开视频| 免费一区二区三区黄色| 国产日产精品久久一区| 久久亚洲中文字幕丝袜长腿| 亚洲国产欧美日韩国产| 蜜桃成人一区二区三区| 国产精品夜色一区二区三区不卡| 日本在线不卡二区三区| av高清不卡一区二区免费在线| 色婷婷激情一区二区三区| 国产一区精品在线免费看| 精品国产91乱码一区二区三区| 伊人亚洲一区二区三区| 亚洲欧洲一区二区免费| 哈昂~不要啊在线观看| 在线观看国产小视频不卡| 99国产精品热久久婷婷| 亚洲欧洲另类美女久久精品| 日韩精品一区二区国产| 在线激情视频一区二区| 中文字幕日韩一区二区| 一区二区三区福利视频在线观看| 国产亚洲精品福利视频| 92午夜福利在线视频| 国产精品第一区第二区| 午夜福利精品在线观看| 18岁未成年禁止观看视频| 欧美精品在线观看不卡一区|