深入淺出AQS之共享鎖模式

2021-09-14 08:26:29 字數 2588 閱讀 2405

在了解了aqs獨佔鎖模式以後,接下來再來看看共享鎖的實現原理。

搞清楚aqs獨佔鎖的實現原理之後,再看共享鎖的實現原理就會輕鬆很多。兩種鎖模式之間很多通用的地方本文只會簡單說明一下,就不在贅述了,具體細節可以參考我的上篇文章深入淺出aqs之獨佔鎖模式

一、執行過程概述

獲取鎖的過程:

當執行緒呼叫acquireshared()申請獲取鎖資源時,如果成功,則進入臨界區。

當獲取鎖失敗時,則建立乙個共享型別的節點並進入乙個fifo等待佇列,然後被掛起等待喚醒。

當佇列中的等待執行緒被喚醒以後就重新嘗試獲取鎖資源,如果成功則喚醒後面還在等待的共享節點並把該喚醒事件傳遞下去,即會依次喚醒在該節點後面的所有共享節點,然後進入臨界區,否則繼續掛起等待。

釋放鎖過程:

當執行緒呼叫releaseshared()進行鎖資源釋放時,如果釋放成功,則喚醒佇列中等待的節點,如果有的話。

二、原始碼深入分析

基於上面所說的共享鎖執行流程,我們接下來看下原始碼實現邏輯:

首先來看下獲取鎖的方法acquireshared(),如下

public final void acquireshared(int arg)
這裡tryacquireshared()方法是留給使用者去實現具體的獲取鎖邏輯的。關於該方法的實現有兩點需要特別說明:

一、該方法必須自己檢查當前上下文是否支援獲取共享鎖,如果支援再進行獲取。

二、該方法返回值是個重點。其

一、由上面的原始碼片段可以看出返回值小於0表示獲取鎖失敗,需要進入等待佇列。其

二、如果返回值等於0表示當前執行緒獲取共享鎖成功,但它後續的執行緒是無法繼續獲取的,也就是不需要把它後面等待的節點喚醒。最後、如果返回值大於0,表示當前執行緒獲取共享鎖成功且它後續等待的節點也有可能繼續獲取共享鎖成功,也就是說此時需要把後續節點喚醒讓它們去嘗試獲取共享鎖。

有了上面的約定,我們再來看下doacquireshared方法的實現:

//引數不多說,就是傳給acquireshared()的引數

private void doacquireshared(int arg)

}//掛起邏輯跟獨佔鎖一樣,不再贅述

if (shouldparkafte***iledacquire(p, node) &&

parkandcheckinterrupt())

interrupted = true;

}} finally

}

獨佔鎖模式獲取成功以後設定頭結點然後返回中斷狀態,結束流程。而共享鎖模式獲取成功以後,呼叫了setheadandpropagate方法,從方法名就可以看出除了設定新的頭結點以外還有乙個傳遞動作,一起看下**:

//兩個入參,乙個是當前成功獲取共享鎖的節點,乙個就是tryacquireshared方法的返回值,注意上面說的,它可能大於0也可能等於0

private void setheadandpropagate(node node, int propagate)

}private void sethead(node node)

最終的喚醒操作也很複雜,專門拿出來分析一下:

注:這個喚醒操作在releaseshare()方法裡也會呼叫。

private void doreleaseshared() 

//如果後繼節點暫時不需要喚醒,則把當前節點狀態設定為propagate確保以後可以傳遞下去

else if (ws == 0 &&

!compareandsetwaitstatus(h, 0, node.propagate))

continue;

}//如果頭結點沒有發生變化,表示設定完成,退出迴圈

//如果頭結點發生變化,比如說其他執行緒獲取到了鎖,為了使自己的喚醒動作可以傳遞,必須進行重試

if (h == head)

break;

}}

接下來看下釋放共享鎖的過程:

public final boolean releaseshared(int arg) 

return false;

}

注:上面的setheadandpropagate()方法表示等待佇列中的執行緒成功獲取到共享鎖,這時候它需要喚醒它後面的共享節點(如果有),但是當通過releaseshared()方法去釋放乙個共享鎖的時候,接下來等待獨佔鎖跟共享鎖的執行緒都可以被喚醒進行嘗試獲取。

三、總結

跟獨佔鎖相比,共享鎖的主要特徵在於當乙個在等待佇列中的共享節點成功獲取到鎖以後(它獲取到的是共享鎖),既然是共享,那它必須要依次喚醒後面所有可以跟它一起共享當前鎖資源的節點,毫無疑問,這些節點必須也是在等待共享鎖(這是大前提,如果等待的是獨佔鎖,那前面已經有乙個共享節點獲取鎖了,它肯定是獲取不到的)。當共享鎖被釋放的時候,可以用讀寫鎖為例進行思考,當乙個讀鎖被釋放,此時不論是讀鎖還是寫鎖都是可以競爭資源的。

深入淺出AQS之元件概覽

之前分析了aqs中的獨佔鎖,共享鎖,條件佇列三大模組,現在從結構上來看看aqs各個元件的情況。深入淺出aqs之獨佔鎖模式 深入淺出aqs之共享鎖模式 深入淺出aqs之條件佇列 前面三篇文章如果之前沒有aqs基礎的話看起來會比較吃力,這篇文章說明一下aqs的基礎知識,方便快速了解aqs。首先aqs的基...

深入淺出之工廠模式

首先說說簡單工廠模式,我用現實中的汽車工廠舉例子,首先有個汽車類的介面叫做car,裡面有個開車的方法叫做drive 然後有個吉利車的類叫做jili,實現了car的介面,還有個奇瑞車的類叫做qirui,也實現了car的介面 因為都是車嘛,當然能開了 inte ce carelse if qirui e...

深入淺出之STL

c stl 標準模板庫 是一套功能強大的 c 模板類,提供了通用的模板類和函式,這些模板類和函式可以實現多種流行和常用的演算法和資料結構,如向量 鍊錶 佇列 棧。c 標準模板庫的核心包括以下三個元件 元件描述 容器 containers 容器是用來管理某一類物件的集合。c 提供了各種不同型別的容器,...