執行緒基礎知識05- ReentrantLock重入鎖
阿新 • • 發佈:2020-09-07
ReentrantLock也叫重入鎖,可以對同一執行緒資源進行重複加鎖。通過lock()方法可以顯式的加鎖,並且再次呼叫lock(),不會出現阻塞的情況
Sync子類提供鎖的基本實現機制
-
非公平鎖的獲取
- 獲取獨佔鎖後,增加狀態碼
//加鎖 final void lock() { if (compareAndSetState(0, 1))//如果是首次,增加鎖狀態碼為1 setExclusiveOwnerThread(Thread.currentThread()); else /** * 呼叫AQS中的acquire方法,加入到同步佇列中 * 迴圈呼叫tryAcquire方法,當前節點的前驅是頭節點時,設定當前節點為頭節點 */ acquire(1); } final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) {//表示當前狀態為空,設定當前執行緒為獨佔鎖執行緒 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) {//當前執行緒和獨佔鎖執行緒相同 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc);//更新狀態 return true; } return false; }
-
釋放鎖操作
- 釋放鎖後更新減少狀態碼,同步狀態為0時,表示鎖釋放成功
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) {//狀態為0時,獨佔執行緒置為空,釋放執行緒 free = true; setExclusiveOwnerThread(null); } setState(c);//更新狀態 return free; }
公平鎖FairSync
-
公平鎖的獲取鎖方法
- 同步佇列的頭節點進行獲取鎖,如果成功,則返回true,如果未獲取成功,返回false
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { /** * 1.當前執行緒節點為頭節點,並通過CAS成功將state設定成acuires值 * 返回true */ if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } /** * 當前執行緒和獨佔執行緒一致時 * 1.更改狀態; * 2.返回獲取鎖成功 */ else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } public final boolean hasQueuedPredecessors() { Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
非公平鎖NonfairSync
- 直接呼叫SYN的nofairTryAcquire方法
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
公平鎖和非公平鎖建立
-
通過傳入true或false,初始化建立公平鎖或非公平鎖
-
預設是不公平鎖
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
public ReentrantLock() {
sync = new NonfairSync();
}
公平鎖和非公平鎖的優缺點
-
公平鎖:
優點:保證了按照鎖的獲取的時間長短,時間最長的先獲取到鎖。會獲取當前節點所在等待佇列的位置,必須按照位置執行。
缺點:
-
因為要判斷前驅,且嚴格按照同步佇列順序,因此效率更低
-
也因為順序執行,所以多次獲取鎖操作,會造成上下文切換冗餘,切換次數更多
-
-
非公平鎖:
優點: 因為只需要判斷狀態碼,因此,同一個鎖再次獲取到的概率比較大,所以鎖切換次數少,效率比較高。保證有更大的吞吐量。
缺點: 同一個鎖的多次呼叫,容易造成,單個鎖呼叫頻繁,執行緒出現“飢餓”狀態;
(圖片摘自《Java併發程式設計藝術》)