AQS,ReentrantLock和ConditionObject
介紹一下AQS:
注意看綠色的方法,這些是對外開放的方法。
另外,AQS是一個CLH變種雙邊佇列,原始的CLH是.net人員設計的,他們設計的時候是讓每個阻塞在佇列上的執行緒不停的自旋,而在java中借鑑了這種設計方式,但是不再是自旋,而是通過LockSupport.park(this);這樣一個方法將執行緒阻塞。
***********************
acquire方法:
其中acquire開頭的方法是AQS預設實現的通用加鎖方法,帶有Interruptibly結尾的是處理打斷狀態的請求方法,不帶的是不處理打斷標誌的方法。帶有shared的是共享鎖的加鎖方法,不帶有的則是獨佔鎖的加鎖方法。
上面是AQS中的acquire方法(AQS實現的這個是公平鎖的獲取方式):獨佔鎖獲取方法,先呼叫tryAcquire方法,如果成功則加鎖成功,如果失敗則執行緒開始排隊,並阻塞自己。tryAcquire方法如下:
方法的註釋解釋的很清楚,子類應該去實現這個方法,因為此方法會被acquire方法呼叫,而獨佔鎖獲取鎖必須呼叫acquire方法,如果你實現的是一個獨佔鎖,那麼你必須實現此方法,如果是共享鎖則不必。
實現此方法時:當返回失敗,則此執行緒應該排隊(直到被另外一個執行緒通過release喚醒或者它被中斷),如果成功則上鎖成功。
******************
release方法:
release方法是AQS釋放阻塞執行緒的方法,讓其去競爭鎖,帶有shared是共享鎖的釋放方法,不帶的則是獨佔鎖的方法。思路一致。這裡看下公平鎖的release方
註釋很清楚,AQS負責釋放阻塞執行緒,子類實現自己的tryRelease方法去釋放鎖。其他的方法就不贅述了。
*************************
介紹下ReentrantLock:
ReentrantLock是實現AQS的獨佔鎖,它內部先是定義了一個抽象同步器Sync實現了AQS,這個方法定義了非公平鎖嘗試獲取鎖的方式(嘗試獲取鎖是不會阻塞的,只會返回成功或失敗)。
然後是公平鎖和非公平鎖:
結合之前AQS的介紹,相信我們一眼就可以看透這兩個類了,非公平鎖的lock方法是自己利用CAS實現的搶佔式加鎖,如果失敗則專用AQS的公平鎖加鎖方式;而公平鎖就簡單多了lock方法呼叫的就是AQS提供的加鎖方式。
而嘗試獲取鎖的方式都是自定義的,前者定義在sync中後者定義在公平鎖子類中。程式碼不復雜,不需要贅述了。
**************************
介紹下ConditionObject:
這個是條件佇列,相信很多人看到這個類的時候是很迷惑的,我也是。別慌先看類的方法:
就倆類方法await和signal,分別是阻塞和喚醒。還有兩個屬性Node,說明這是個雙端連結串列結構的組織,因為有前驅和後驅兩個節點。用大母腳趾頭想都能想到這個類是幹啥用的。就不贅述了。
---------------------------------------------
ReentrantLock測試:
ConditionObject測試:
執行緒2和執行緒3是前兩個進入鎖的執行緒因為各自呼叫count+1後,但是不滿足Condition的條件,因此被阻塞到Condition1物件上,然後後面進來的所有執行緒都滿足Condition佇列的要求,因此可以直接執行。可以看到除了第2和第3執行緒外,其他執行緒都是順序執行(按照非公平鎖的CLH佇列順序執行)。
呼叫Lock的newCondition方法會建立一個繫結到此Lock上的阻塞佇列Condition,這個Condition又叫做條件佇列,當沒有滿足此Condition的條件前,鎖是由獲得Lock的當前執行緒佔有,當滿足Condition的條件後,可以呼叫Condition.await方法,這樣當前執行緒會以原子的方式釋放掉此Lock,然後阻塞在Condition的阻塞佇列中,直到被同一個Condition喚醒或者此執行緒被打斷。
!!!!
如有錯誤,請指正。