可重入鎖機制和源碼解析


一.概述:

鎖分為可重入鎖和不可重入鎖,這兩者的區(qū)別是什么?
可重入鎖就是當一個線程獲得了某個對象的實例并進入一個方法A,這個線程在沒有釋放鎖的情況下能否再次進入方法A,就是可重入鎖和不可重入鎖的區(qū)別。

  • 可重入鎖:能再次進入方法A,什么情況下需要再次進入方法A,對嘍,就是遞歸調(diào)用這個加鎖方法執(zhí)行運算的時候,像synchronized和Reentrantlock都是可重入鎖。
  • 不可重入鎖:不能再次進入方法A,Mutex(互斥鎖)是不可重入鎖。

注:在看我這篇文章之前,建議先閱讀以下幾篇文章,對重入鎖有一個大概的了解,順序也按照我給出的順序來閱讀,我這篇文章只是對可重入鎖的源碼、CAS、AQS等進行一個總結(jié),對于沒有看過AQS或可重入鎖的朋友來說不太容易懂。踏下心來看完我推薦的文章,基本對可重入鎖(甚至互斥鎖及其他鎖)有一個比較深入的了解。

1.先學習一下可重入鎖的使用方法
https://blog.csdn.net/u012545728/article/details/80843595
https://blog.csdn.net/soonfly/article/details/70918802

2.簡單介紹可重入鎖的原理,就像作者起的題目一樣:輕松學習java可重入鎖,這篇文章把可重入鎖的機制解釋的非常易懂生動。
https://blog.csdn.net/yanyan19880509/article/details/52345422

3.解釋完了,直接看源碼吧,這篇文章是我看過比較好的一篇介紹可重入鎖源碼的文章:
http://www.itdecent.cn/p/7e1a1903d467

4.看完第三篇,是不是想了解下AQS:強烈推薦下面這篇講解AQS的文章,媽呀,當我看完這篇文章之后,那叫一個通透,終于知道什么叫大牛,就是不單技術(shù)好,博客寫的也NB
AQS:https://www.cnblogs.com/waterystone/p/4920797.html

5.讀完AQS,是不是也想掃盲下CAS,那來吧:這篇把CAS連帶Unsafe類將的比較通俗易懂
CAS:https://blog.csdn.net/mmoren/article/details/79185862

6.最后,記不記得第三篇文章提到了CAS自旋volatile變量,如果還感興趣的朋友可以參考下這篇文章:
https://blog.csdn.net/holmofy/article/details/73824757

二.可重入鎖機制及源碼總結(jié):

可重入鎖分公平鎖和非公平鎖:線程老老實實在同步隊列排隊機制的鎖叫公平鎖,在之前線程釋放鎖期間可以加塞的鎖叫非公平鎖,可重入鎖的默認鎖是非公平鎖。讀完上面幾篇文章后,可結(jié)合我的總結(jié)的源碼圖進行鞏固(圖片尺寸比較大,下載看更清楚,我傳的是高清圖),公平鎖和非公平鎖機制類似,因此這里只拿不公平鎖舉例。

可重入鎖里面有三個內(nèi)部類,Sync同步類,非公平鎖類,公平鎖類,其中Sync類給公平鎖和非公平鎖實現(xiàn)了一些共有方法,比如tryRelease()等方法,也給非公平鎖實現(xiàn)了一些特定的比如nonfairTryAcquire()方法(還真是非公平啊...)。

可重入鎖最基本最重要的方法就是lock()加鎖和unLock()釋放鎖方法,這里重點介紹這兩個方法。

可重入鎖源碼圖.jpg

三.自定義同步器AQS:

談到并發(fā),不得不談Reentrantlock,而談到ReentrantLock,不得不談AbstractQueuedSynchronizer,就像名字描述的,抽象隊列同步器定義了一套多線程訪問共享資源的同步器框架,許多類的實現(xiàn)都依賴它,比如
ReentrantLock、Semaphore、CountDownLatch等。

AQS維護了一個volatile state(代表共享資源)和FIFO線程等待隊列(多線程競爭資源隊列),不同自定義同步器競爭共享資源的方式不同,但自定義同步器在實現(xiàn)時只需實現(xiàn)共享資源state的獲取與釋放方式即可,至于線程等待隊列的維護,AQS已經(jīng)實現(xiàn)好了,主要有下面幾個方法:

  • isHeldExclusively():該線程是否正在獨占資源。只有用到condition才需要去實現(xiàn)它。
  • tryAcquire(int):獨占方式。嘗試獲取資源,成功則返回true,失敗則返回false。
  • tryRelease(int):獨占方式。嘗試釋放資源,成功則返回true,失敗則返回false。
  • tryAcquireShared(int):共享方式。嘗試獲取資源。負數(shù)表示失?。?表示成功,但沒有剩余可用資源;正數(shù)表示成功,且有剩余資源。
  • tryReleaseShared(int):共享方式。嘗試釋放資源,如果釋放后允許喚醒后續(xù)等待結(jié)點返回true,否則返回false。

AQS定義兩種資源共享方式:獨占模式(EXCLUSIVE,只有一個線程能執(zhí)行,如Reentrantlock)和共享模式(Semaphore、CountDownLatch)。一般來說,自定義同步器要么是獨占的,要么是共享的,也可兼有兩種模式,比如ReentrantReadWritelock。我們實現(xiàn)某種模式只需要繼承AQS,實現(xiàn)tryAcquire和tryRelease方法即可,這也是AQS不是接口而是類的原因,用什么模式只要實現(xiàn)那個模式對應的方法。

四.CAS:

CAS全稱CompareAndSwap,核心算法是這樣的:

CAS(V,E,N)//V-要更新的變量;E-舊值,或者叫期望值;N-要替換的新值;

在替換為新值之前,比較下變量V是否是當前的期望值,如果相等,替換,不相等,不做動作或重復檢測。

鎖分為悲觀鎖和樂觀鎖,在多線程環(huán)境下,

  • 悲觀鎖:如果在執(zhí)行動作之前會認為可能發(fā)生鎖沖突,在執(zhí)行動作之前加鎖的機制為悲觀鎖,對待操作是一種悲觀的態(tài)度;
  • 樂觀鎖:在執(zhí)行動作之前認為不會發(fā)生鎖沖突,也不加鎖,即無所操作,一旦發(fā)生所沖突再去解決沖突的機制為樂觀鎖,對待操作是一種樂觀的態(tài)度;

而CAS就是一種樂觀鎖,他是一種系統(tǒng)級語言,因為系統(tǒng)原語的字節(jié)碼指令執(zhí)行時連續(xù)的,所以說CAS操作時一條CPU的原子指令操作,不會造成數(shù)據(jù)不一致的問題。

Unsafe類
我們接著深入一下,CAS在Java的實現(xiàn)環(huán)境中必須依賴鮮為人知的Unsafe類,可以理解為CAS操作是Unsafe類的一些方法。Unsafe這個類的方法都是被native()方法修飾的,意思是它的方法可以向操作C指針一樣直接操作物理內(nèi)存,直接調(diào)用操作系統(tǒng)底層資源執(zhí)行相應任務。Unsafe類里CAS的相關(guān)操作涉及的方法如下:

//o為指定對象,offset為對象內(nèi)存的偏移量,偏移量迅速定位字段并設置或獲取該字段的值,
expected表示期望值,x表示要設置的值,下面3個方法都通過CAS原子指令執(zhí)行操作。
public final native boolean compareAndSwapObject(Object o, long offset,Object expected, Object x);
public final native boolean compareAndSwapInt(Object o, long offset,int expected,int x);
public final native boolean compareAndSwapLong(Object o, long offset,long expected,long x);
  • 線程掛起與恢復
    在Java中,線程的掛起與恢復的相關(guān)操作被封裝在LockSuport類中,但是其底層的還是通過Unsafe類的park()和unPark()方法實現(xiàn)的,
  • CAS使用場景
    從Java1.5開始,提供了java.util.concurrent.atomic包,在該包中有很多基于CAS操作實現(xiàn)的類,比如
AtomicBoolean:原子更新布爾類型
AtomicInteger:原子更新整型
AtomicLong:原子更新長整型

比如AtomicInteger的原子自增方法getAndAddInt()就是實現(xiàn)了CAS操作,從而保證了線程安全,有興趣的朋友可以去看下源碼。

后記:由于能力有限,若有錯誤或者不當之處,還請大家批評指正,一起學習交流!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

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