ReentrantLock 原理分析

2021-09-09 08:33:52 字數 3179 閱讀 5378

public void lock()
這是lock的原始碼,呼叫的其實是sync這個物件的lock函式,而sync是reentrantlock內部類sync的乙個物件例項,他有兩種實現nonfairsync(非公平鎖)和fairsync(公平鎖)

先看公平鎖的lock函式

final void lock()
只有一行**,呼叫的是aqs的acquire函式

public final void acquire(int arg)
按流程,先進入tryacquire

protected final boolean tryacquire(int acquires) 

}//如果狀態不為0,則判斷是否為已經獲得鎖的物件進行重入鎖操作

else if (current == getexclusiveownerthread())

//獲取鎖失敗返回false

return false;

}

在獲取鎖的時候有兩步核心操作hasqueuedpredecessors(判斷當前等待獲取鎖的執行緒佇列是否為空)和compareandsetstate(將同步器狀態標記為accquires)

public final boolean hasqueuedpredecessors()
如果當前沒有執行緒在等待鎖則返回true,如果有則返回false

protected final boolean compareandsetstate(int expect, int update)
呼叫unsafe物件的cas函式為同步器的狀態進行修改,確保該操作為原子操作(同意時間若有多個執行緒進行該操作則只有乙個執行緒返回成功)

這兩步完成以後,就可以將當前執行緒標記為獨佔執行緒,該執行緒釋放鎖之前,再有執行緒來嘗試獲取鎖都會進入下一步acquirequeued(addwaiter(node.exclusive), arg)

先看addwaiter

private node addwaiter(node mode) 

}enq(node);

return node;

}

將當前執行緒封裝成node物件,判斷tail物件是否為空,如果不為空則呼叫原子操作compareandsettail,將該節點設為tail,如果該操作失敗了,則呼叫enq函式

private node enq(final node node)  else }}

}

該函式為乙個死迴圈,如果沒有tail則新建head同時設定head為tail,然後一直迴圈到這個節點加入佇列為止,加入成功後再將該節點返回出來,進入下一步操作acquirequeued

final boolean acquirequeued(final node node, int arg) 

if (shouldparkafte***iledacquire(p, node) &&

parkandcheckinterrupt())

interrupted = true;

}} finally

}

可以看到這個函式裡也有乙個死迴圈,然後有兩個關鍵函式shouldparkafte***iledacquire(獲取鎖失敗後是否應該掛起)和parkandcheckinterrupt(掛起並檢查中斷狀態)

先看parkandcheckinterrupt

private final boolean parkandcheckinterrupt()
掛起當前執行緒,並返回了執行緒中斷狀態 

然後是shouldparkafte***iledacquire

private static boolean shouldparkafte***iledacquire(node pred, node node)  while (pred.waitstatus > 0);

pred.next = node;

} else

return false;

}

非公平鎖的lock

final void lock()
可以看到他會先嘗試修改一下狀態,如果成功就直接設定當前執行緒為獨佔執行緒

他的acquire也跟公平鎖不同

protected final boolean tryacquire(int acquires)
final boolean nonfairtryacquire(int acquires) 

}else if (current == getexclusiveownerthread())

return false;

}

對比公平鎖,非公平鎖少了hasqueuedpredecessors這乙個判斷,他在嘗試獲取鎖的時候不會判斷當前是否有執行緒處於等待狀態

public void unlock()
unlock呼叫的是同步器的release函式

public final boolean release(int arg) 

return false;

}

先呼叫tryrelease函式,如果返回成功,則喚醒頭節點執行緒

protected final boolean tryrelease(int releases) 

setstate(c);

return free;

}

將狀態值減去要釋放的值,結果為零且執行tryrelease這個函式的當前執行緒為同步器的獨佔執行緒則釋放成功,將獨佔執行緒置為null,狀態置為0

private void unparksuccessor(node node) 

if (s != null)

locksupport.unpark(s.thread);

}

先找head節點的next節點,如果其為空或者waitstatus大於0則從tail節點開始往回遍歷,找到排在最起碼的waitstatus大於0的節點,呼叫locksupport.unpark喚醒該節點

ReentrantLock 原理分析

鎖是一段 當執行緒執行到這段 時執行緒阻塞 掛起 或者進入輪詢 使用方式 reentrantlock lock new reentrantlock 預設建立非公平鎖 lock.lock 鎖住的 邏輯 lock.unlock 執行到 lock 方法時做的事情 建立的非公平鎖 1 判斷當前執行緒能否獲取...

ReentrantLock實現原理分析

本文只對reentrantlock中獲取鎖和釋放鎖的方法進行分析,其它方法不做分析。final void lock protected final boolean tryacquire int acquires else if current getexclusiveownerthread retu...

ReentrantLock之AQS原理與原始碼詳解

abstractqueuedsynchronizer,抽象佇列同步器 給大家畫乙個圖先,看一下reentrantlock和aqs之間的關係。abstractqueuedsynchronizer為reentrantlock的靜態內部類 2 預設為非公平鎖 3 最終會呼叫abstractqueuedsy...