ReentrantLock之AQS原理與源碼詳解

ReentrantLock和AQS的關係


ReentrantLock使用

圖片描述

AbstractQueuedSynchronizer,抽象隊列同步器;給你們畫一個圖先,看一下ReentrantLock和AQS之間的關係。
圖片描述源碼分析

AbstractQueuedSynchronizer爲ReentrantLock的靜態內部類
圖片描述post

lock()源碼分析

圖片描述

二、默認爲非公平鎖
圖片描述spa

三、最終會調用AbstractQueuedSynchronizer子類NonfairSync.lock()方法;
圖片描述
lock()方法作了什麼事呢?
首先須要知道AQS會維護兩個變量state(初始值0)、exclusiveOwnerThread(初始值null),源碼以下,記錄線程狀態與當前加鎖線程
圖片描述線程

圖片描述

線程1跑過來調用ReentrantLock的lock()方法嘗試進行加鎖,這個加鎖的過程,直接就是用CAS操做將state值從0變爲1。
若是以前沒人加過鎖,那麼state的值確定是0,此時線程1就能夠加鎖成功。
一旦線程1加鎖成功了以後,就能夠設置當前加鎖線程是本身。因此你們看下面的圖,就是線程1跑過來加鎖的一個過程。
圖片描述隊列

可重入鎖

state記錄加鎖次數,爲0時釋放鎖圖片

鎖的互斥是如何實現的?

線程2跑過來一下看到,哎呀!state的值不是0啊?因此CAS操做將state從0變爲1的過程會失敗,由於state的值當前爲1,說明已經有人加鎖了!
接着線程2會看一下,是否是本身以前加的鎖啊?固然不是了,「加鎖線程」這個變量明確記錄了是線程1佔用了這個鎖,因此線程2此時就是加鎖失敗。
接着,線程2會將本身放入AQS中的一個等待隊列,由於本身嘗試加鎖失敗了,此時就要將本身放入隊列中來等待,等待線程1釋放鎖以後,本身就能夠從新嘗試加鎖了
因此你們能夠看到,AQS是如此的核心!AQS內部還有一個等待隊列,專門放那些加鎖失敗的線程!
一樣,給你們來一張圖,一塊兒感覺一下:
圖片描述
源碼
線程2進來加鎖失敗後,會進入等待隊列;等待隊列爲鏈表
圖片描述
圖片描述
圖片描述
接着,線程1在執行完本身的業務邏輯代碼以後,就會釋放鎖!他釋放鎖的過程很是的簡單,就是將AQS內的state變量的值遞減1,若是state值爲0,則完全釋放鎖,會將「加鎖線程」變量也設置爲null!
整個過程,參見下圖:
圖片描述get

釋放鎖源碼:

LockSupport.unpark(s.thread);
圖片描述
圖片描述
接下來,會從等待隊列的隊頭喚醒線程2從新嘗試加鎖。
好!線程2如今就從新嘗試加鎖,這時仍是用CAS操做將state從0變爲1,此時就會成功,成功以後表明加鎖成功,就會將state設置爲1。
此外,還要把「加鎖線程」設置爲線程2本身,同時線程2本身就從等待隊列中出隊了。
最後再來一張圖,你們來看看這個過程。
圖片描述同步

Node存儲等待線程隊列

圖片描述

參考資料https://juejin.im/post/5c07e5...源碼

相關文章
相關標籤/搜索