多線程-aqs與reentrantLock

AQS和ReentrantLock

ReentrantLock的lock特點

  1. 異常的鎖是包含死鎖和活鎖,死鎖無法解決,活鎖可以通過錯開執行時間解決

  2. lock的特點:可打斷,可重入,可設置超時時間,可設置鎖類型(公平非公平),支持多變量,支持鎖類型(讀,寫)

  3. 以上都是基礎概念,例子就不寫了,至於多變量condition,這個我也沒用過,大概意思,用對應的condition去喚醒,下面是例子

    1684118027772

AQS框架的樣子

  1. AbstractQueuedSychronizer 同步隊列,他有一個屬性state表示鎖的狀態,數字表示獲得鎖的次數,利用cas改變其數值;其中有倆吧鎖,獨佔鎖,共享鎖(相鄰的讀讀共享,讀寫互斥), 它的鎖都支持公平和非公平兩種模式 ;內部有一個隊列,fifo,格式大概是,有一個head指向隊首,一個tail指向隊尾,具體結構如下圖;條件變量實現等待喚醒機制(我也不太懂,沒用過);內部有一個thread exclusiveOwnerThread記錄持有鎖的線程;

  2. 1684200284575

  3. 其主要是實現的功能:(這個就是一些概念,知道就行)

    1. 功能

      1、實現阻塞獲取鎖 acquire 拿不到鎖就去阻塞 等待鎖被釋放再次獲取鎖

      2、實現非阻塞嘗試獲取鎖 tryAcquire 拿不到鎖則直接放棄

      3、實現獲取鎖超時機制

      4、實現通過打斷來取消

      5、實現獨佔鎖及共享鎖

      6、實現條件不滿足的時候等待

  4. 自定義實現AQS框架:如下圖感覺沒啥意思,也沒有可重入的實現

  5. 1684200741843

ReentrantLock的加鎖和解鎖流程

  1. 首先看他和AQS關係:關係如下,圖中包含公平鎖,非公平鎖

  2. 1684200107138

  3. 1684200841086

  4. 1684200891149

  5. 看nonfairSync的加鎖過程:以下面的例子爲例,大概情況爲(//這裏少了排隊中隊列元素的屬性,Node.waitStatus,)

    1. 首先t1進來加鎖,此時無競爭
    2. ti拿到了鎖t2來了
    3. t1釋放了鎖,t2開始拿鎖
    4. t1拿到了鎖,t2t3在排隊

    1684201072553

    1684201083743

    1684201133043

    1684201181572

    16842011977751684201233632

  6. 線程打斷:線程存在一箇中斷標記,這個標記的含義是記錄自己是否被別的線程中斷過,清除既標記製爲false;那如何看這個標記呢t1.interrupted(),具體代碼如下

    這段英文是介紹說這個方法被其他線程中斷時會調用這個方法

    1684202380061

    這段介紹的是當前線程以獨佔鎖形式被中斷,如果中斷則終止,否則繼續嘗試拿鎖,失敗排隊

    1684202513179

    拿鎖失敗後的過程,排隊拿鎖

    1684203057541

  7. 看解鎖流程,先看幾張圖,大致流程如下ti持有鎖,t2排隊,t1釋放鎖,t2持有鎖,這裏還有一個Node。waitStatus的狀態。當狀態爲-1,作用是隊首節點拿到鎖後是否喚醒下一個節點

    1684203438821

    1684203444714

  8. 讀讀併發需注意的問題:這個是別人寫的例子,證明讀讀併發,讀寫互斥

    1684204149885

  9. 讀寫鎖之寫鎖上鎖過程:由於讀寫互斥,多以寫鎖加鎖時要麼鎖沒有別人持有,或者鎖重入纔可以加上鎖;關於鎖的數據結構,比如32bit表示鎖,前16位爲讀鎖,後16位爲寫鎖;

    具體流程如下:reentrantLock的writeLock
    這裏直接從tryAcqurie方法開始,首先獲取當前線程,或許鎖的狀態state,獲取寫鎖的狀態(後16位),如果state不等於0,要判斷當前是不是寫鎖,如果w==0則代表沒上過寫鎖,只是讀鎖,直接返回false,如果是寫鎖則判斷佔有這把鎖的是不是當前線程,如果託不是則返回false;如果這個判斷過了則判斷重入次數是否超過最大限制,如果沒有就設置state,返回true;如果state=0則是第一次來,那就要區分是否是公平鎖還是非公平鎖,如果非公平則直接拿鎖,公平則排隊,如果隊裏沒人則直接拿鎖,如果隊裏有人則加鎖失敗返回false

    1684204254689

  10. 讀寫鎖之讀鎖上鎖過程

    具體流程如下:reentrantLock之讀鎖上鎖
    首先獲取當前線程,當前鎖狀態state,如果exclusiveCount(C)!=0代表是寫鎖,並且獨佔鎖還不是當前線程,則返回-1;如果上訴情況沒有發生則看上鎖次數,如果上鎖次數小於最大值,並且不排隊,並且cas(c,c+share_unit)如果都滿足則進入讀鎖加鎖判定中,在這裏如果讀鎖r=0,則代表第一個線程第一次加鎖,如果讀鎖r!=0,但是第一個讀鎖線程是當前線程,或者相鄰的讀鎖進入,都返回1

    1684204276642

  11. 關於搶鎖的時候非公平搶了幾次鎖

    第一次:使用無阻塞的cas去搶鎖,第二次,如對之前如何上一個節點是head則再搶一次,搶不到就去排隊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章