java多線程:並發包中ReentrantLock鎖的公平鎖原理


一:鎖的原理結構

(1)鎖對象內部維護了一個同步管理器的對象AbstractQueuedSynchronizer,AbstractOwnableSynchronizer

(2)該對象其實是一個抽象類,具體的鎖的管理器繼承該抽象類

(3)該抽象類的關鍵屬性有:---->Thread exclusiveOwnerThread(獲取鎖的線程對象)

----> Node head(首節點,正在擁有當前鎖的線程構造的Node對象)

---->Node tail(尾巴節點,等待獲取鎖的線程構造的雙向鏈表結構的隊列的最后一個節點)

---->int state(當前該鎖被線程爭搶的狀態,如果state=0,表示無線程爭搶該鎖,如果state>0則表示已經有線程擁有該鎖)

 

二:鎖中的Node隊列的結構

(1)所有的線程在執行到獲取鎖的代碼的部分,都會調用同步管理器的lock()方法,如果有線程獲取鎖,則將該線程構造成node對象,添加到隊列尾部,並調用系統命令阻塞當前線程。也就是代碼執行到這,當前線程就不再執行。

(2)擁有鎖的線程,在釋放鎖的時候,會喚醒自己的后繼節點的線程,讓其爭搶鎖。

(3)Node的內部結構屬性

--->int waitStatus(當前node的線程在爭搶鎖過程的狀態標識)

--->Node prev(當前node的上一個node的引用,前驅節點)

--->Node next(當前node的下一個INITALnode的引用,后繼節點)

--->Thread thread(當前node所代表的線程的線程對象)

--->Node nextWaiter(下一個等待着的node)

(4)node等待狀態的的含義

CANCELLED =  1:由於在同步隊列中等待的線程等待超時或被中斷,需要從同步隊列中取消等待,節點進入該狀態不會再變化

SIGNAL    = -1:后繼節點線程處於等待狀態,而當前節點的線程如果釋放了同步狀態或者被取消,將會通知后繼節點,使后繼節點得以運行。

CONDITION = -2:在等待隊列中,節點線程等待在Condition上,當其他線程對Condition調用了signal()方法后,該節點將會從等待隊列中轉移到同步隊列中。加入到對同步狀態的獲取中。

PROPAGATE = -3:表示下一次共享式同步狀態獲取將會無條件被傳播下去。

INITIAL=0:初始化狀態

 

三:公平鎖和非公平鎖的區別

(1)公平鎖的鎖獲取,嚴格按照等待順序進行鎖獲取,在獲取鎖的時候有一個判斷hasQueuedPredeccssors(),同步隊列中是否有前驅節點在等待獲取鎖,如果有,則放棄獲取鎖,而是添加到隊尾,排隊獲取鎖

(2)非公平鎖,是獲取鎖的順序是隨機的,甚至,有的線程可能會一直無法獲取鎖,出現線程飢餓情況。

(3)公平鎖的性能往往沒有非公平鎖的性能高,因為它需要排隊,則需要進行程序狀態的切換,要比非公平鎖的切換次數多。

(4)公平鎖:在獲取鎖的時候,先檢查是否已經有隊列形成。如果有,則加入隊列。按順序排隊,獲取鎖。

(5)非公平鎖:在獲取鎖的時候,會多次嘗試獲取鎖,而不着急加入隊列排隊,更有主動權獲取鎖。如果多次獲取也沒獲取成功,也加入排隊,此時和公平鎖一樣。其兩者的區別在於:非公平鎖,加大了新晉線程搶到鎖的概率。

 

四:鎖的獲取和釋放的過程圖

 

 

【LockSupport】工具的api

park():阻塞當前線程,如果調用unpark(Thread thread)方法或者當前線程被中斷,才能從park()方法返回。

parkNanos(long nanos):阻塞當前線程,最長不超過nanos納秒,返回條件在park()的基礎上增加了超時返回。

parkUntil(long deadline):阻塞當前線程,直到deadline時間(從1970年開始到deadline時間的毫秒數)

unpark(Thread thread):喚醒處於阻塞狀態的線程thread

park(Object blocker):阻塞當前線程,如果調用unpark(Thread thread)方法或者當前線程被中斷,才能從park(Object blocker)方法返回。blocker用於問題排查和系統監控。

parkNanos(Object blocker,long nanos):阻塞當前線程,最長不超過nanos納秒,返回條件在park(Object blocker)的基礎上增加了超時返回。blocker用於問題排查和系統監控。

parkUntil(Object blocker,long deadline):阻塞當前線程,直到deadline時間(從1970年開始到deadline時間的毫秒數),blocker用於問題排查和系統監控。

 

 

======================公平鎖和非公平鎖=================

 轉載:全文地址請點擊:https://blog.csdn.net/qyp199312/article/details/70598480?utm_source=copy 

公平鎖:

  • 公平和非公平鎖的隊列都基於鎖內部維護的一個雙向鏈表,表結點Node的值就是每一個請求當前鎖的線程。公平鎖則在於每次都是依次從隊首取值。
  • 鎖的實現方式是基於如下幾點:
    • 表結點Node和狀態statevolatile關鍵字。
    • sum.misc.Unsafe.compareAndSet的原子操作(見附錄)。

非公平鎖:

  • 在等待鎖的過程中, 如果有任意新的線程妄圖獲取鎖,都是有很大的幾率直接獲取到鎖的。

ReentrantLock鎖都不會使得線程中斷,除非開發者自己設置了中斷位。
ReentrantLock獲取鎖里面有看似自旋的代碼,但是它不是自旋鎖。
ReentrantLock公平與非公平鎖都是屬於排它鎖。

公平鎖和非公平鎖

ReentrantLock 的公平鎖和非公平鎖都委托了 AbstractQueuedSynchronizer#acquire 去請求獲取。

public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
  • tryAcquire 是一個抽象方法,是公平與非公平的實現原理所在。
  • addWaiter 是將當前線程結點加入等待隊列之中。公平鎖在鎖釋放后會嚴格按照等到隊列去取后續值而非公平鎖在對於新晉線程有很大優勢
  • acquireQueued 在多次循環中嘗試獲取到鎖或者將當前線程阻塞。
  • selfInterrupt 如果線程在阻塞期間發生了中斷,調用 Thread.currentThread().interrupt() 中斷當前線程。

ReentrantLock 對線程的阻塞是基於 LockSupport.park(this); (見 AbstractQueuedSynchronizer#parkAndCheckInterrupt)。 先決條件是當前節點有限次嘗試獲取鎖失敗。

公平鎖和非公平鎖在說的獲取上都使用到了 volatile 關鍵字修飾的state字段, 這是保證多線程環境下鎖的獲取與否的核心。
但是當並發情況下多個線程都讀取到 state == 0時,則必須用到CAS技術,一門CPU的原子鎖技術,可通過CPU對共享變量加鎖的形式,實現數據變更的原子操作。
volatile 和 CAS的結合是並發搶占的關鍵。

 

CAS和volatile, Java並發的基石

volatile 是Java語言的關鍵字, 功能是保證被修飾的元素(共享變量):

任何進程在讀取的時候,都會清空本進程里面持有的共享變量的值,強制從主存里面獲取;
任何進程在寫入完畢的時候,都會強制將共享變量的值寫會主存。
volatile 會干預指令重排。
volatile 實現了JMM規范的 happen-before 原則。

在多核多線程CPU環境下, CPU為了提升指令執行速度,在保證程序語義正確的前提下,允許編譯器對指令進行重排序。也就是說這種指令重排序對於上層代碼是感知不到的,我們稱之為 processor ordering.

JMM 允許編譯器在指令重排上自由發揮,除非程序員通過 volatile等 顯式干預這種重排機制,建立起同步機制,保證多線程代碼正確運行。見文章:Java並發:volatile內存可見性和指令重排

當多個線程之間有互相的數據依賴的之后, 就必須顯式的干預這個指令重排機制


CAS是CPU提供的一門技術。在單核單線程處理器上,所有的指令允許都是順序操作;但是在多核多線程處理器上,多線程訪問同一個共享變量的時候,可能存在並發問題。

使用CAS技術可以鎖定住元素的值。Intel開發文檔, 第八章
編譯器在將線程持有的值與被鎖定的值進行比較,相同則更新為更新的值。
CAS同樣遵循JMM規范的 happen-before 原則。
JAVA CAS原理深度分析博客

公平鎖和非公平鎖在說的獲取上都使用到了 volatile 關鍵字修飾的state字段, 這是保證多線程環境下鎖的獲取與否的核心。
但是當並發情況下多個線程都讀取到 state == 0時,則必須用到CAS技術,一門CPU的原子鎖技術,可通過CPU對共享變量加鎖的形式,實現數據變更的原子操作。
volatile 和 CAS的結合是並發搶占的關鍵。

--------------------- 本文來自 平菇蝦餃 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/qyp199312/article/details/70598480


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM