ReentrantLock 加鎖解鎖過程分析

一、ReetrantLock

     1、 公平鎖,ReentrantLock reentrantLock = new ReentrantLock(true);  reentrantLock.lock();設置鎖爲公平鎖。  

         

            1-1、 內部獲取定義的變量state,判斷是否爲0,如果爲0,則代表鎖已經被佔用

           1-2、判斷是否需要排隊:

                   ① 判斷隊首,隊尾是否相同,隊列未初始化時,隊列爲空,隊首隊尾相同,返回fasle。

                   ② 隊列已經初始化,但是隊列中只有一個空的node節點,沒有排隊的線程,隊首隊尾相同,返回fasle。

                   ③ 隊列已經初始化,隊首空node下有一個新的node,並且是這個node中的線程獲取鎖,返回false。

這裏如果返回false,!hasQueuedPredecessors返回true,則代表可以獲取鎖

       1-3 調用unsafe方法,修改state的值爲1。

     1-4、設置持有鎖的線程爲當前線程,加鎖成功,返回true。!tryAcquire(arg) 結果爲false,執行 selfInterrupt();回覆線程實際的執行狀態。

   2、 如果1 中的條件不成立,則標識獲取鎖失敗,需要進行排隊嘗試。

      2-1 addWaiter(Node.EXCLUSIVE), arg),嘗試初始化排隊隊列。

         ① 如果隊列已經初始化,隊尾增加一個node,維護一個雙向鏈表。

         ② 如果隊列未初始化,則需要初始化一個隊列,這裏是一個死循環,初始化完成跳出,判斷隊尾爲null,則在隊首初始化一個線程爲空的node(表示隊列中可能正在運行的線程,或者是持有鎖的線程),把,新的node追加到初始化的node之後。

 維護一個如下圖一樣的隊列,隊首的node的thread一直爲null。

å¨è¿éæå¥å¾çæè¿°

3 獲取隊列

   3-1 查看一下當前node的前一個是否是隊首,如果不是則 證明前面已經有人在排隊了,直接park

   3-2 如果前一個是隊首,則在此嘗試獲取鎖,如果能 獲取,則返回表示加鎖成功。

   3-3 如果都沒有成功,則修改前一個waitStatus,爲-1,如果大於0,表示前一個node已經被cancled,則移除前一個node,直到找到一個可用的node。並且LockSupport.park(this);線程讓出cpu,等待喚醒。

二、解鎖過程:reentrantLock.unlock();

 1、嘗試解鎖,比較簡單,對state -1,如果值爲0,則代表可以釋放,清空當前運行線程,並返回true

  2、unparkSuccessor(h)釋放下一個線程     

if (ws < 0) compareAndSetWaitStatus(node, ws, 0); 這個是將頭節點設置狀態設置爲0,

① 下次節點進纔會把頭改爲-1,才證明有新的線程加入,否則一直爲0,

② 下面代碼判斷的時候如果只有一個頭節點,node.next也爲null,頭尾一個節點,t!= null,但是頭的節點的thread爲null,如果①步驟不改,調用unpark會報錯。

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