深入理解ReentrantLock

2021-10-09 05:13:11 字數 3374 閱讀 8674

reentrantlock基於aqs的獨佔模式,預設採用非公平鎖,是一種可重入鎖。

可以在構造方法中指定是公平鎖還是非公平鎖

arrayblockingqueue中的**:

final reentrantlock lock;

private

final condition notfull;

public

void

put(e e)

throws interruptedexception

finally

}

public

reentrantlock()

public

reentrantlock

(boolean fair)

非公平鎖主要體現在獲取鎖時不判斷是否有人在排隊,直接cas操作嘗試獲取鎖

static

final

class

nonfairsync

extends

sync

// acquire是父類aqs中的方法

public

final

void

acquire

(int arg)

protected

final

boolean

tryacquire

(int acquires)

}final

boolean

nonfairtryacquire

(int acquires)

}// 如果鎖被占用,判斷是不是自己占用的鎖,這體現了重入性

else

if(current ==

getexclusiveownerthread()

)return

false

;}

static

final

class

fairsync

extends

sync

// acquire是父類aqs中的方法

public

final

void

acquire

(int arg)

/** * fair version of tryacquire. don't grant access unless

* recursive call or no waiters or is first.

*/protected

final

boolean

tryacquire

(int acquires)

}// 如果鎖被占用,判斷是不是自己占用的鎖,這體現了重入性

else

if(current ==

getexclusiveownerthread()

)return

false

;// 獲取失敗,後面就是執行aqs的排隊方法

}}

公平鎖和非公平鎖只有兩處不同:

非公平鎖在呼叫 lock 後,直接呼叫cas方法進行一次搶鎖,如果這個時候恰巧鎖沒有被占用,那麼直接就獲取到鎖返回了。

非公平鎖在 cas 失敗後,和公平鎖一樣都會進入到 tryacquire 方法,在 tryacquire 方法中,如果發現鎖這個時候被釋放了(state == 0),非公平鎖會直接 cas 搶鎖,但是公平鎖會判斷等待佇列是否有執行緒處於等待狀態,如果有則不去搶鎖,乖乖排到後面。

公平鎖和非公平鎖就這兩點區別,如果這兩次 cas 都不成功,那麼後面非公平鎖和公平鎖是一樣的,都要進入到clh佇列等待喚醒(aqs中已實現)。

非公平鎖會有更好的效能,因為它的吞吐量比較大。當然,非公平鎖讓獲取鎖的時間變得更加不確定,可能會導致在阻塞佇列中的執行緒長期處於飢餓狀態

兩者都是可重入鎖

可重入鎖概念是:自己可以再次獲取自己的內部鎖。比如乙個執行緒獲得了某個物件的鎖,此時這個物件鎖還沒有釋放,當其再次想要獲取這個物件的鎖的時候還是可以獲取的,如果不可鎖重入的話,就會造成死鎖。同乙個執行緒每次獲取鎖,鎖的計數器都自增1,所以要等到鎖的計數器下降為0時才能釋放鎖。

synchronized 依賴於 jvm , reentrantlock 依賴於 api

reentrantlock提供了一種能夠中斷等待鎖的執行緒的機制。通過lock.lockinterruptibly()來實現這個機制。也就是說正在等待的執行緒可以選擇放棄等待,改為處理其他事情。

**reentrantlock可以指定是公平鎖還是非公平鎖,而synchronized只能是非公平鎖。**所謂的公平鎖就是先等待的執行緒先獲得鎖。

reentrantlock可實現選擇性通知,排程執行緒更加靈活

用reentrantlock類可以繫結多個condition例項可以實現選擇性通知,而synchronized在使用notify、notifyall()方法進行通知時,被通知的執行緒是由 jvm 選擇的,相當於整個lock物件中只有乙個condition例項,所有的執行緒都註冊在它乙個身上。如果執行notifyall()方法的話就會通知所有處於等待狀態的執行緒這樣會造成很大的效率問題,而condition例項的signalall()方法只會喚醒註冊在該condition例項中的所有等待執行緒。

synchronized 異常就會釋放鎖,而 reentrantlock 異常需要在 finally 裡 unlock

效能已不是選擇標準

在jdk1.6之前,synchronized 的效能是比 reentrantlock 差很多。具體表示為:synchronized 關鍵字吞吐量隨執行緒數的增加,下降得非常嚴重。而reentrantlock 基本保持乙個比較穩定的水平。這也側面反映了, synchronized 關鍵字還有非常大的優化餘地。後續的技術發展也證明了這一點,在 jdk1.6 之後 jvm 團隊對 synchronized 關鍵字做了很多優化。jdk1.6 之後,synchronized 和 reentrantlock 的效能基本是持平了。jdk1.6之後,效能已經不是選擇synchronized和reentrantlock的影響因素了!而且虛擬機器在未來的效能改進中會更偏向於原生的synchronized,所以還是提倡在synchronized能滿足你的需求的情況下,優先考慮使用synchronized關鍵字來進行同步!優化後的synchronized和reentrantlock一樣,在很多地方都是用到了cas操作。

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...

mysql 索引深入理解 深入理解MySql的索引

為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...