ReentrantLock 實(shí)現(xiàn)了隱式鎖synchronized基本的行為和語義默垄,并且提供了額外的一些能力。
一個(gè)ReentrantLock被最后一次成功獲取到鎖的線程持有怠益,直到線程釋放他呛伴。
可重入的意思是一個(gè)線程如果成功調(diào)用lock()方法并且返回,
成功的獲取了鎖盔憨,當(dāng)前線程未釋放鎖時(shí),如果當(dāng)前線程再次獲取鎖將會(huì)立即返回讯沈。
在調(diào)用線程內(nèi)部可以使用isHeldByCurrentThread檢查是是否被當(dāng)前線程持有郁岩。
通過getHoldCount查看當(dāng)前線程持有鎖有多少個(gè)狀態(tài),即重入次數(shù)。
ReentrantLock有公平和非公平兩種问慎,即獨(dú)占模式也分為兩種萍摊。ReentrantLock內(nèi)部類中分別都對(duì)其進(jìn)行了實(shí)現(xiàn)。
默認(rèn)構(gòu)造函數(shù)是非公平模式如叼,也可通過傳入可選的參數(shù)指定公平實(shí)現(xiàn)冰木。公平模式下鎖更偏向?qū)?zhí)行權(quán)授予最長(zhǎng)-等待線程。
非公平模式下不保證任何訪問順序笼恰。
公平模式下的鎖具有更低的吞吐量(通常來說就是很慢)比非公平鎖踊沸,但是這樣保證了用較少時(shí)間上的差異來獲得鎖以及保護(hù)線程不會(huì)饑餓。
注意:公平鎖不保證線程調(diào)度的公平性挖腰,因此,多個(gè)線程使用同一把鎖练湿,其中一個(gè)線程可能獲取成功了多次而其他活動(dòng)線程還沒什么進(jìn)展也也沒持有鎖猴仑。
這句話的意思是盡管當(dāng)前線程多次獲取鎖經(jīng)歷了排隊(duì)等待這些過程,但是依然完成了任務(wù)并且成功獲取了多次鎖肥哎,說明被線程調(diào)度到了辽俗,而其他活動(dòng)的線程的任務(wù)沒有進(jìn)展,盡管他們不需要鎖篡诽,這是由于線程調(diào)度導(dǎo)致的崖飘。
同樣注意沒有時(shí)間參數(shù)的tryLock()方法也不滿足公平性。盡管有其他線程在等待杈女,如果他獲取的時(shí)候這個(gè)鎖是空閑的朱浴,仍然會(huì)獲取成功。因?yàn)閠ryLock直接調(diào)用的是nonfairTryAcquire达椰。
ReentrantLock有三個(gè)內(nèi)部類:
Sync:鎖的基類實(shí)現(xiàn)繼承AQS翰蠢,子類實(shí)現(xiàn)是下面的公平鎖FairSync和鎖NonfairSync
FairSync:公平鎖實(shí)現(xiàn)
NonfairSync:非公平鎖實(shí)現(xiàn)
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();
/**非公平的tryLock。tryAcquire被子類實(shí)現(xiàn)啰劲,但是tryLock和tryAcquire都需要nonfair所以放在基類中梁沧,這樣即便指定模式是公平鎖,其tryLock也是非公平的
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//獲取AQS狀態(tài)蝇裤,getState 具有volatile讀語義
int c = getState();
//c=0 表示鎖是空閑的
if (c == 0) {
//原子性的修改狀態(tài)為acquires(共享資源)廷支,acquires根據(jù)實(shí)現(xiàn)不同而表現(xiàn)不同,在ReentrantLock 0表示空閑大于1表示已經(jīng)被獲取和重入的次數(shù)栓辜,在semaphore表現(xiàn)為共享資源的數(shù)量恋拍。
if (compareAndSetState(0, acquires)) {
//成功設(shè)置排他擁有線程為當(dāng)前線程
setExclusiveOwnerThread(current);
//成功直接返回表示直接獲取到鎖
return true;
}
}
//已經(jīng)獲取到鎖則增加重入次數(shù)并立即返回:這就是被稱為重入鎖的原因
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;
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
、**首先進(jìn)行l(wèi)ock 藕甩。失敗則調(diào)用AQS的acquire芝囤,acquire會(huì)調(diào)用NonfairSync#tryAcquire最后調(diào)用nonfairTryAcquire
* 可以發(fā)現(xiàn)非公平鎖首先進(jìn)行了兩次的lock,如果成功則直接返回。不會(huì)經(jīng)過入隊(duì)悯姊,park羡藐,unpark線程上下文切換,這是是非公平鎖快的原因悯许。
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
//直接調(diào)用父類的acquire仆嗦,acquire首先調(diào)用FairSync#tryAcquire
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//與非公平鎖不同的是公平鎖首先會(huì)判斷是否有線程已經(jīng)在排隊(duì)等待,沒有才會(huì)直接嘗試修改狀態(tài)先壕。
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
//AbstractQueuedSynchronizer#hasQueuedPredecessors
/**
查詢是否已經(jīng)有線程在排隊(duì)瘩扼,并且等待時(shí)間比當(dāng)前線程長(zhǎng)
調(diào)用這個(gè)方法等價(jià)于 (但是這個(gè)方法可能更有效率)getFirstQueuedThread() != Thread.currentThread() &&hasQueuedThreads()
注意:因?yàn)榫€程中斷和超時(shí)可能發(fā)生在任何時(shí)候,返回true垃僚,即隊(duì)列中有線程集绰,但是其他線程也可能在當(dāng)前線程之前進(jìn)行aquire操作
返回false,即隊(duì)列為空谆棺,也有可能其他線程在這個(gè)線程之前進(jìn)行了入隊(duì)操作
這個(gè)方法被設(shè)計(jì)成公平鎖去避免沖突栽燕。一個(gè)同步器的方法應(yīng)該返回false,tryAcquireShared應(yīng)該返回一個(gè)負(fù)數(shù)改淑,如果這個(gè)方法返回true(除非他是一個(gè)重入的acquire操作)碍岔。
例如tryAcquire方法在一個(gè)公平的可重入的獨(dú)占鎖應(yīng)該像下面這種形式(和ReentrantLock#FairSync#tryAcquire語義一抹一樣):
* protected boolean tryAcquire(int arg) {
* if (isHeldExclusively()) {
* // A reentrant acquire; increment hold count
* return true;
* } else if (hasQueuedPredecessors()) {
* return false;
* } else {
* // try to acquire normally
* }
* }}</pre>
* 返回 true:如果當(dāng)前線程前有排隊(duì)的線程
false:如果當(dāng)前線程時(shí)隊(duì)列的頭部或者隊(duì)列是空的
**/
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
//1、h !=t 只有當(dāng)隊(duì)列尚未被初始化朵夏,AQS被初始化蔼啦,head和tail都沒被賦值時(shí)返回false,即非公平鎖第一次進(jìn)入tryAquire仰猖,hasQueuedPredecessors返回false捏肢,接著tryAquire調(diào)用compareAndSetState成功。
//第二個(gè)線程進(jìn)入 同樣hasQueuedPredecessors返回false饥侵,compareAndSetState失敗猛计,調(diào)用addWaiter,初始化head和tail爆捞,head和tail都不相等奉瘤。
/**
2、當(dāng)頭結(jié)點(diǎn)和尾節(jié)點(diǎn)不相等并且 如果head節(jié)點(diǎn)的next節(jié)點(diǎn)s不為空煮甥,并且s不是當(dāng)前線程盗温。代表頭節(jié)點(diǎn)執(zhí)行完后s節(jié)點(diǎn)有可能被執(zhí)行。當(dāng)前線程無法參與競(jìng)爭(zhēng)成肘,所以返回true卖局。這種情況發(fā)生在當(dāng)前節(jié)點(diǎn)是第一次入隊(duì)的情況。
3双霍、當(dāng)頭結(jié)點(diǎn)和尾節(jié)點(diǎn)不相等并且 如果head節(jié)點(diǎn)的next節(jié)點(diǎn)s不為空砚偶,并且s是當(dāng)前線程批销。代表頭節(jié)點(diǎn)執(zhí)行完后s節(jié)點(diǎn)(當(dāng)前線程)有可能被執(zhí)行所以返回fasle。(代表上一層可以去競(jìng)爭(zhēng)獨(dú)占狀態(tài))染坯。這種情況發(fā)生在當(dāng)前節(jié)點(diǎn)已經(jīng)入隊(duì)的情況下均芽。
4、當(dāng)頭結(jié)點(diǎn)和尾節(jié)點(diǎn)不相等并且 如果head節(jié)點(diǎn)的next節(jié)點(diǎn)s為空单鹿,那么直接返回true掀宋,代表頭節(jié)點(diǎn)后面沒有節(jié)點(diǎn)。即當(dāng)前線程不是頭節(jié)點(diǎn)的next節(jié)點(diǎn)仲锄。返回true劲妙。不直接參與競(jìng)爭(zhēng),這種情況發(fā)生在(有可能頭節(jié)點(diǎn)后面的節(jié)點(diǎn)被取消儒喊,或者新入隊(duì)的節(jié)點(diǎn)next尚未賦值)
**/
return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
}
總結(jié)下這個(gè)方法:以上四點(diǎn)保證了如果有其他的線程在頭節(jié)點(diǎn)的next上等待并且head節(jié)點(diǎn)的next節(jié)點(diǎn)不是當(dāng)前節(jié)點(diǎn)時(shí)镣奋,那么這個(gè)線程不能直接參與競(jìng)爭(zhēng),只能加入同步隊(duì)列怀愧,否則如果當(dāng)前head節(jié)點(diǎn)的next節(jié)點(diǎn)指向自己侨颈,將直接執(zhí)行compareAndset設(shè)置狀態(tài)。
這樣保證了除第一個(gè)線程外其他線程都必須經(jīng)過排隊(duì)等待head的next指向自己掸驱,所以要實(shí)現(xiàn)公平鎖的首要條件就是使用hasQueuedPredecessors 作為判斷條件之一肛搬。
總結(jié)下:
1没佑、公平鎖和非公平鎖最大的差異在tryAcquire是否會(huì)檢查隊(duì)列中是否有線程在等待
2毕贼、非平鎖首先會(huì)嘗試修改2次,進(jìn)行搶占而不管是否已經(jīng)有線程在排隊(duì)蛤奢。
3鬼癣、公平鎖的第一個(gè)線程將會(huì)被直接獲取到鎖執(zhí)行,當(dāng)且僅當(dāng)?shù)谝粋€(gè)線程沒有執(zhí)行完畢啤贩,第二個(gè)線程才會(huì)進(jìn)入排隊(duì)待秃。執(zhí)行addWaiter和acquireQueued
先順著acquire方法分析下去,然后再逐個(gè)分析ReentrantLock的方法痹屹。
``` /**
只能在獨(dú)占模式下使用acquire方法(因?yàn)閍ddWaiter傳入的mode是exclusive章郁,忽略中斷)。并且至少調(diào)用一次tryAcquire志衍。
調(diào)用acquire成功的話會(huì)立即返回否則暖庄,線程會(huì)被入隊(duì),
可能重復(fù)的阻塞和解阻塞楼肪,調(diào)用tryAcquire直到成功培廓。(第一次進(jìn)來無法獲取鎖,阻塞春叫。后面有可能其他節(jié)點(diǎn)線程獲取鎖發(fā)生異常肩钠,cancelAquire會(huì)調(diào)用unparkSuccessor泣港,
當(dāng)前節(jié)點(diǎn)有可能被喚醒,判斷head不是自己前驅(qū)价匠,進(jìn)行取消節(jié)點(diǎn)裁剪后当纱,則再次阻塞,直到head是自己的前驅(qū)并且調(diào)用release方法重置狀態(tài)霞怀,喚醒自己惫东,線程再次被喚醒)
這個(gè)方法可以用來實(shí)現(xiàn)Lock接口的lock語義
**/
public final void acquire(int arg) {
//tryAcquire失敗后添加到隊(duì)列末尾并且排隊(duì)等待,如果tryAcquire成功立即返回毙石,表示成功獲取到鎖廉沮。
//tryAcquire失敗:1.head的next沒有指向當(dāng)前線程徐矩,hasQueuedPredecessors返回false 滞时。
//2.如果tryAcquire返回true,acquire立即返回 2.無線程排隊(duì)滤灯,hasQueuedPredecessors返回false坪稽。
//前一個(gè)線程未釋放狀態(tài),compareAndSetState失敗鳞骤,tryAcquire返回false窒百,這才開始第一次入隊(duì)酥泛。
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
總結(jié):tryAcquire成功將立即返回獲取到鎖僻肖,失敗則進(jìn)行排隊(duì)。下面說下tryAcquire成功失敗的幾種情況:
tryAcquire成功:
1逆航、鎖剛剛新建完成初始化美旧,第一個(gè)線程來請(qǐng)求鎖渤滞,毫無疑問 hasQueuedPredecessors中 head=null,tail=null 榴嗅,hasQueuedPredecessors中h != t返回false妄呕,tryAcquire調(diào)用compareAndSet成功獲取到鎖。
2嗽测、檔head節(jié)點(diǎn)的next指向一個(gè)節(jié)點(diǎn)绪励,這個(gè)節(jié)點(diǎn)hasQueuedPredecessors返回false,因?yàn)樽约壕褪堑鹊米罹玫?唠粥,于是不停的調(diào)用tryAcquire疏魏,獲取到鎖。
tryAcquire失斕啊:
1蠢护、新線程加入:判斷hasQueuedPredecessors為true,加入等待隊(duì)列進(jìn)行等待养涮。
2葵硕、等待隊(duì)列中的線程雖然head的next節(jié)點(diǎn)指向自己?jiǎn)紊韈ompareAndset設(shè)置失敗眉抬。
//添加新的節(jié)點(diǎn)到等待隊(duì)列中
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
//快速嘗試入隊(duì),否則使用自旋入隊(duì)
//將tail復(fù)制給pred
Node pred = tail;
if (pred != null) {
node.prev = pred;
//設(shè)置尾節(jié)點(diǎn)為node
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);//確保隊(duì)列為空的情況下
return node;
}
//自旋入隊(duì)操作,
private Node enq(final Node node) {
for (;;) {
//第一個(gè)節(jié)點(diǎn)首次入隊(duì)首先執(zhí)行懈凹,初始化空節(jié)點(diǎn)
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
//入隊(duì)
node.prev = t;//首先保證將前驅(qū)節(jié)點(diǎn)賦值給prev蜀变,保證前驅(qū)穩(wěn)定。所以在遍歷next=null情況下使用prev向前遍歷是安全可靠的介评。
if (compareAndSetTail(t, node)) {
t.next = node;//這一步操作是库北,非線程安全 可能節(jié)點(diǎn)已經(jīng)在隊(duì)列上了 t.next仍然為null,對(duì)其他線程不可見
return t;
}
}
}
}
總結(jié)下:enq在第二個(gè)線程入隊(duì)時(shí)才延遲初始化head節(jié)點(diǎn)和當(dāng)且線程節(jié)點(diǎn)们陆。后續(xù)入隊(duì)操作直接執(zhí)行else后面的操作寒瓦,并且t.next = node 不能保證已經(jīng)入隊(duì)的節(jié)點(diǎn)next不為null,這也是hasQueuedPredecessors判斷next==null的原因之一坪仇。
/**
* Convenience method to interrupt current thread.設(shè)置中斷狀態(tài)
*/
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
/**
在獨(dú)占且不可中斷模式下已經(jīng)排隊(duì)的節(jié)點(diǎn)acquire方法杂腰。
同樣也被用于條件等待方法await
**/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//判斷當(dāng)前節(jié)點(diǎn)的前驅(qū)是否是頭節(jié)點(diǎn),是才進(jìn)行tryAcquire調(diào)用子類的方法去判斷并修改狀態(tài)椅文,且成功后設(shè)置隊(duì)列Head為當(dāng)節(jié)點(diǎn)并且將head節(jié)點(diǎn)出隊(duì)喂很。
//當(dāng)且僅當(dāng)當(dāng)前線程被喚醒后,重新循環(huán)皆刺,判斷p==head==true少辣,再進(jìn)行tryAquire
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;//標(biāo)記失敗狀態(tài)
return interrupted;//acquire 中根據(jù)返回的中斷狀態(tài)設(shè)置值當(dāng)前線程的中斷。
}
//設(shè)置signal狀態(tài)羡蛾,在下次自旋中判斷返回true漓帅,調(diào)用parkAndCheckInterrupt設(shè)置中斷狀態(tài),并park林说。
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//執(zhí)行到這里表明已經(jīng)被前驅(qū)節(jié)點(diǎn)喚醒煎殷,并繼續(xù)自旋獲取鎖
//如果被中斷設(shè)置中斷狀態(tài)屯伞,但是并不處理
interrupted = true;
}
} finally {
//
if (failed)
cancelAcquire(node);
}
}
/**
檢查和更新acquire失敗的節(jié)點(diǎn)的狀態(tài)腿箩,如果一個(gè)節(jié)點(diǎn)應(yīng)該阻塞則返回true。
主要控制acquireQueued的死循環(huán)劣摇。
* Checks and updates status for a node that failed to acquire.
* Returns true if thread should block. This is the main signal
* control in all acquire loops. Requires that pred == node.prev.
*
* @param pred node's predecessor holding status
* @param node the node
* @return {@code true} if thread should block
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
//已經(jīng)設(shè)置了前驅(qū)節(jié)點(diǎn)的珠移,SIGNAL 直接返回true,park這個(gè)線程
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
* 前驅(qū)節(jié)點(diǎn)已經(jīng)被設(shè)置為取消狀態(tài)末融,需要修改prev節(jié)點(diǎn)钧惧,這里 有幾個(gè)問題
* 1、為什么是在這里修改勾习? 因?yàn)樵诰€程即將進(jìn)入park的時(shí)候需要保證自己能被喚醒,通常是誰喚醒自己呢浓瞪?
前驅(qū)節(jié)點(diǎn),但是不總是前驅(qū)節(jié)點(diǎn)巧婶。所以需要保證前驅(qū)節(jié)點(diǎn)是活著的乾颁。這里僅僅是嘗試涂乌,就算重新設(shè)置了前驅(qū)節(jié)點(diǎn),
設(shè)置后的前驅(qū)節(jié)點(diǎn)也會(huì)發(fā)生異常而取消英岭,所以在喚醒的時(shí)候還會(huì)有一次查找判斷
* 2湾盒、為什么在取消的時(shí)候修改了一次prev,next屬性這里還要設(shè)置一次诅妹?
next屬性已經(jīng)由線程取消的時(shí)候被設(shè)置了罚勾,發(fā)生在這個(gè)步驟前。cancelAcquire方法可以同時(shí)被多個(gè)方法調(diào)用發(fā)送競(jìng)爭(zhēng)吭狡,所以要使用CAS修改尖殃,但是不保證一定成功。所以在每個(gè)線程之中需要再進(jìn)行保證划煮。
* 3分衫、修改其他節(jié)點(diǎn)的prev,next屬性是線程安全的嗎般此?
是的蚪战。進(jìn)入這個(gè)方法時(shí)判斷的是node節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)的狀態(tài)。假設(shè)這個(gè)節(jié)點(diǎn)的前面也有個(gè)node判斷前驅(qū)節(jié)點(diǎn)是取消狀態(tài)铐懊,然后嘗試修改邀桑。那么這個(gè)節(jié)點(diǎn)的線程找到的是他的前驅(qū)節(jié)點(diǎn)的前面的第一個(gè)沒有被取消的節(jié)點(diǎn)。
并不是我們這個(gè)線程所找到的第一個(gè)未取消的節(jié)點(diǎn)科乎,如果本節(jié)點(diǎn)后面有線程在檢查也一樣壁畸,最終大家都只負(fù)責(zé)修改自己的前驅(qū),刪除掉的是自己那一塊區(qū)域茅茂,所以并不會(huì)發(fā)生競(jìng)爭(zhēng)捏萍。
總結(jié):觀察cancelAcquire和unparkSuccessor最終完成將取消節(jié)點(diǎn)出隊(duì)的都是這部分操作
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/* 獲取獨(dú)占鎖的線程在進(jìn)來的時(shí)候waitStatus都是0。表示這個(gè)線程需要設(shè)置信號(hào)空闲,
然后在下一次自旋中被park令杈。下次自旋中仍然會(huì)查看是否自己是head節(jié)點(diǎn)是的話就嘗試修改狀態(tài)。這樣盡最大努力去嘗試然后再park
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
//park 并且返回當(dāng)前線程是否被中斷
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
/**
* Cancels an ongoing attempt to acquire.
* 取消正在進(jìn)行的acquire碴倾,cancelAcquire總是在finally語句塊中被調(diào)用
* 發(fā)生異常進(jìn)行取消是基本算法的健壯性目標(biāo)之一逗噩。cancelAcquire 首先應(yīng)滿足,取消當(dāng)前節(jié)點(diǎn)后應(yīng)能不影響其他線程的執(zhí)行跌榔,也就是應(yīng)該喚醒下一個(gè)線程异雁。
*并且應(yīng)該重新設(shè)置AQS隊(duì)列,將被取消的節(jié)點(diǎn)進(jìn)行清理僧须,以提高隊(duì)列的性能纲刀,因?yàn)樵趩拘岩粋€(gè)線程時(shí)也會(huì)首先判斷隊(duì)列的狀態(tài)并刪除取消的節(jié)點(diǎn)。
*但是這一操作不應(yīng)該由釋放鎖的線程來做因?yàn)樗氖虑橐呀?jīng)做完了担平,清理隊(duì)列應(yīng)該由發(fā)生異常的線程進(jìn)行清理示绊。所以cancelAcquire總是在finally語句塊中芥挣。
*
* @param node the node
*/
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
//獲取到當(dāng)節(jié)點(diǎn)前第一個(gè)狀態(tài)沒有設(shè)置為取消的節(jié)點(diǎn),并且跳過取消的節(jié)點(diǎn)
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
//predNext 即為第一個(gè)找到的沒有設(shè)置為取消狀態(tài)的節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)耻台。
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);//完成一部分出隊(duì)空免,仍保留prev引用
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);//完成一部分出隊(duì),仍保留prev引用
} else {
//
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
1.當(dāng)前節(jié)點(diǎn)是tail節(jié)點(diǎn)時(shí)設(shè)置tail為pred盆耽,自己未獲取到鎖蹋砚,不需要喚醒next節(jié)點(diǎn)。
注意:當(dāng)前節(jié)點(diǎn)不可能是head節(jié)點(diǎn)
2摄杂、pred是head節(jié)點(diǎn)時(shí)坝咐,node節(jié)點(diǎn)故障了直接喚醒他后面的線程 unparkSuccessor(node);unpark之后進(jìn)入aquiredQueued判斷當(dāng)前前驅(qū)是head(已經(jīng)設(shè)置node.prev=pred)成功。CAS的時(shí)候分為兩種情況:
2.1 CAS成功:head恰好釋放鎖調(diào)用release方法析恢,當(dāng)然head線程也在unparkSuccessor觀察到head.next.waitStatus>0 墨坚,
并且整個(gè)替換了,而不是只替換next屬性映挂。然后這個(gè)節(jié)點(diǎn)就變成了head節(jié)點(diǎn)泽篮,其實(shí)這就是正常的release流程。
這里只是說明不管CAS成功還是失敗都不會(huì)影響到刪除取消的節(jié)點(diǎn)柑船,都是做的一樣的操作對(duì)結(jié)果本身沒有影響帽撑。
在head線程刪除取消狀態(tài)的節(jié)點(diǎn)的時(shí)候,也只刪除離自己最近的節(jié)點(diǎn)鞍时,直到找到waitstatus<0 的節(jié)點(diǎn)亏拉。
2.2 CAS失敗,因?yàn)槟嫖。谑沁M(jìn)入shouldParkAfterFailedAcquire及塘,由正常節(jié)點(diǎn)的線程去設(shè)置新的prev屬性和新前驅(qū)節(jié)點(diǎn)的后next屬性。因?yàn)槟菢幼鍪蔷€程安全的(查看shouldParkAfterFailedAcquire)锐极。
3笙僚、pred不是首節(jié)點(diǎn),當(dāng)前節(jié)點(diǎn)也不是tail溪烤。在pred的status為SIGNAL并且pred的thread不為空(判斷pred是否已經(jīng)取消)味咳,嘗試設(shè)置 pred的next指向 node的next屬性庇勃。
這里都是使用的CAS不保證成功設(shè)置檬嘀。并且就算compareAndSetNext(pred, predNext, next);成功,也只是完成了刪除節(jié)點(diǎn)的一部分操作责嚷,prev屬性并沒有沒設(shè)置鸳兽。
這里只是盡自己最大努力做一點(diǎn)事情,真正的將已經(jīng)取消節(jié)點(diǎn)(或者說完成一半出隊(duì))出隊(duì)發(fā)生在罕拂,unparkSuccessor的時(shí)候揍异,head節(jié)點(diǎn)會(huì)檢查next節(jié)點(diǎn)是否已經(jīng)取消全陨,最后將離自己最近的一些取消節(jié)點(diǎn)出隊(duì)。
4衷掷、為什么這里只設(shè)置next屬性辱姨,而不修改prev屬性呢?為什么會(huì)在這里設(shè)置next屬性呢戚嗅?
我認(rèn)為有以下原因:
1雨涛、prev被設(shè)計(jì)為可靠的屬性,在unparkSuccessor懦胞,shouldParkAfterFailedAcquire替久,cancelAcquire都在被遍歷,如果此時(shí)對(duì)prev進(jìn)行修改可能導(dǎo)致競(jìng)爭(zhēng)躏尉,喚醒線程蚯根、其他線程的取消都可能出問題。
而在shouldParkAfterFailedAcquire已經(jīng)提到修改prev和next是按段修改的胀糜。每段都由一個(gè)線程負(fù)責(zé)颅拦,不會(huì)引起遍歷修改這樣的競(jìng)爭(zhēng)情況發(fā)生。假設(shè)shouldParkAfterFailedAcquire
在修改的時(shí)候另外一個(gè)node正在unparkSuccessor教藻,并且這個(gè)node的next已經(jīng)被取消矩距,那么最終被unpark的線程也會(huì)執(zhí)行shouldParkAfterFailedAcquire,最終修改prev和next來釋放取消的節(jié)點(diǎn)怖竭。
2锥债、只是盡最大努力修改
總結(jié):cancelAcquire 只是設(shè)置取消狀態(tài),保證最大努力交付(設(shè)置next的值痊臭,設(shè)置prev整個(gè)隊(duì)列的狀態(tài)將受到影響)哮肚。真正做事的是shouldParkAfterFailedAcquire和unparkSuccessor,因?yàn)樗麅刹拍鼙WC這么做是安全的广匙。
shouldParkAfterFailedAcquire直接進(jìn)行整個(gè)節(jié)點(diǎn)的賦值允趟,將取消節(jié)點(diǎn)踢出去,cancelAcquire只是設(shè)置next的值鸦致,或者交給shouldParkAfterFailedAcquire潮剪,shouldParkAfterFailedAcquire同時(shí)將prev和next都修改了。
作用域:cancelAcquire作用于發(fā)生異常的node分唾,shouldParkAfterFailedAcquire入隊(duì)的等待的線程抗碰,unparkSuccessor 作用于喚醒當(dāng)前節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn)的時(shí)候。
所以: 應(yīng)該是是三個(gè)步驟 1.設(shè)置狀態(tài)(cancelAcquire) 2.shouldParkAfterFailedAcquire(park前檢查) 3.unparkSuccessor(unpark前檢查)绽乔。三步來減少取消節(jié)點(diǎn)對(duì)隊(duì)列性能的影響弧蝇。
``` //ReentrantLock#unlock
public void unlock() {
sync.release(1);
}
//AQS#release,獨(dú)占鎖釋放。
public final boolean release(int arg) {
if (tryRelease(arg)) {//首先由子類釋放狀態(tài)和OwnerThread
Node h = head;//AQS 更關(guān)注的是隊(duì)列
/**
只有當(dāng)head不為空的情況下并且head的狀態(tài)不為0才喚醒繼任者線程。
1看疗、h為空表明只有一個(gè)一個(gè)線程使用過鎖并且沒有發(fā)生任何競(jìng)爭(zhēng)沙峻,
隊(duì)列的head和tail都沒初始化,直接返回true两芳,釋放成功摔寨。
1.1當(dāng)這種情況發(fā)生時(shí)有第二個(gè)線程進(jìn)行爭(zhēng)搶鎖,hasQueuedPredecessors為true怖辆,compareAndSetState為false祷肯,調(diào)用addWaiter,進(jìn)入acquireQueued,
判斷p == head ==true,并且再次tryAcquire進(jìn)行compareAndSetState失敗疗隶,然后被park佑笋,最后第一個(gè)線程釋放狀態(tài),也會(huì)調(diào)用unparkSuccessor斑鼻,但是當(dāng)前head節(jié)點(diǎn)是一個(gè)空節(jié)點(diǎn)并沒有Thread在其中蒋纬。即使是這樣
unparkSuccessor喚醒的是head的next節(jié)點(diǎn),而釋放鎖的線程不是head坚弱,thread為null的線程才是當(dāng)前head蜀备,所以第二個(gè)線程依然可以被喚醒并成為head。這里說明了當(dāng)前執(zhí)行的線程不總是head線程荒叶,
喚醒下一個(gè)節(jié)點(diǎn)的線程也不總是head節(jié)點(diǎn)的線程碾阁。當(dāng)前釋放鎖的線程可能不是head節(jié)點(diǎn),也沒有進(jìn)入隊(duì)列中些楣。
2脂凶、h不為空,h的waitStatus =0 意味著沒有后續(xù)節(jié)點(diǎn)需要被喚醒否則waitStatus=Node.SINGAL,表示有繼任節(jié)點(diǎn)愁茁,當(dāng)前的節(jié)點(diǎn)的waitStatus=Node.SINGAL只能由后續(xù)節(jié)點(diǎn)設(shè)置
**/
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
//false 表示釋放鎖失敗蚕钦,可能當(dāng)前釋放鎖的線程和獲取鎖的線程不是同一個(gè),當(dāng)然tryRelease 可選拋出還是不拋出異常鹅很。這里返回false只是穩(wěn)妥的方式嘶居。
//以便其他方法在調(diào)用時(shí)可以使用這個(gè)判斷標(biāo)志作為依賴而拋出其他異常或者設(shè)置新的標(biāo)志,例如后面講到fullRelease的時(shí)候會(huì)說到
return false;
}
//ReentrantLock#Sync#tryRelease
protected final boolean tryRelease(int releases) {
//state是共享變量為什么這里不用加鎖呢促煮?很簡(jiǎn)單只有獲取到鎖的線程才能釋放邮屁,這里其實(shí)只當(dāng)前鎖線程才能釋放
int c = getState() - releases;
//持有鎖的線程是當(dāng)前線程,否則拋出異常菠齿。
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
/**
* Wakes up node's successor, if one exists.
*
* @param node the node
*/
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
//嘗試在unpark前清除node當(dāng)前的等待狀態(tài)(由Node.SIGNAL 變?yōu)?)佑吝,失敗和被等待線程修改都沒有關(guān)系,這個(gè)操作不重要泞当。
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
//下一個(gè)節(jié)點(diǎn)為null或者被取消則迹蛤,從tail節(jié)點(diǎn)向前民珍,進(jìn)行掃描直到找到waitStatus<=0 (最后一個(gè)襟士,離head最近的那一個(gè))即需要被喚醒盗飒,
//同時(shí)將找到的節(jié)點(diǎn)賦值給node.next 實(shí)際上對(duì)其中狀態(tài)>0被取消的節(jié)點(diǎn)進(jìn)行了裁剪,但是只設(shè)置了node的next屬性并未設(shè)置prev屬性陋桂。
//只有一個(gè)地方是用來徹底釋放取消節(jié)點(diǎn)的逆趣。即在shouldParkAfterFailedAcquire中。
//這里首先進(jìn)行next屬性的嘗試嗜历,但是因?yàn)閚ext節(jié)點(diǎn)不總是可靠宣渗,有可能節(jié)點(diǎn)被取消或者next屬性值還沒被賦值。所以使用next屬性實(shí)際上是一種優(yōu)化
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//找到next節(jié)點(diǎn)后喚醒他
if (s != null)
LockSupport.unpark(s.thread);
}
好了公平鎖完完整的流程就走完了梨州。下面繼續(xù)分析ReentrantLock其他的方法痕囱。
獲取鎖除非當(dāng)前線程被中斷
如果當(dāng)前鎖沒有被其他線程持有,則立即返回并且設(shè)置hold count 為1
如果當(dāng)前線程持有這個(gè)鎖暴匠,hold count加1 并且立即返回
如果當(dāng)前鎖被其他線程持有鞍恢,當(dāng)前線程將變得不會(huì)被線程調(diào)度,假死直到下面兩種情況之一發(fā)生:
1.當(dāng)前線程主動(dòng)獲取鎖(被前驅(qū)節(jié)點(diǎn)喚醒)
2.其他線程調(diào)用 Thread.interrupt 中斷這個(gè)線程(在線程獲取鎖的時(shí)候被中斷)
主動(dòng)獲取鎖成功和lock方法效果是一樣的每窖,如果線程在等待的過程中被中斷將拋出 InterruptedException帮掉,并且當(dāng)前線程的中斷狀態(tài)被重新設(shè)置
此方法具有優(yōu)先檢測(cè)中斷的能力
**/
//#ReentrantLock#lockInterruptibly
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
獨(dú)占式的獲取鎖,中斷的時(shí)候終止窒典。
通過首先檢查中斷狀態(tài)蟆炊,然后調(diào)用至少一次的tryAquire,在成功的時(shí)候返回瀑志。否則這個(gè)線程被入隊(duì)涩搓,可能重復(fù)的阻塞或者解阻塞,(第一次進(jìn)來無法獲取鎖劈猪,阻塞缩膝。后面有可能其他節(jié)點(diǎn)線程獲取鎖發(fā)生異常,cancelAquire會(huì)調(diào)用unparkSuccessor岸霹,
當(dāng)前節(jié)點(diǎn)有可能被喚醒疾层,判斷head不是自己前驅(qū),進(jìn)行取消節(jié)點(diǎn)裁剪后贡避,則再次阻塞痛黎,直到head是自己的前驅(qū)并且調(diào)用release方法重置狀態(tài),喚醒自己刮吧,線程再次被喚醒)
然后調(diào)用tryAcquire湖饱, 直到成功獲取到鎖或者這個(gè)線程被中斷。
**/
public final void acquireInterruptibly(int arg)
throws InterruptedException {
//首先判斷中斷狀態(tài)
if (Thread.interrupted())
throw new InterruptedException();
//tryAquire不再分析杀捻,公平鎖和非公平鎖的區(qū)別在于是調(diào)用hasQueuedPredecessors井厌,此處是公平鎖
//tryAquire 判斷隊(duì)列是否有節(jié)點(diǎn),CAS設(shè)置狀態(tài)等不再前面已經(jīng)說過。
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
/**
獨(dú)占獲取并且響應(yīng)中斷
和acquireQueued 對(duì)比
acquireQueued 有返回值 參數(shù)為Node 忽略中斷 入隊(duì)操作在外層aquire中(方便被重用)
doAcquireInterruptibly 無返回值 參數(shù)為aquire的數(shù)量 顯示拋出InterruptedException 入隊(duì)操作在自己方法體中
**/
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//注意:被喚醒之后如果檢測(cè)中斷狀態(tài)被設(shè)置仅仆,才接著拋出異常
throw new InterruptedException();
}
} finally {
if (failed) //拋出InterruptedException 后 failed=true器赞,執(zhí)行取消流程。
cancelAcquire(node);
}
}
**總結(jié):doAcquireInterruptibly嘗試獲取鎖時(shí)會(huì)檢測(cè)中斷狀態(tài)墓拜,拋出異常港柜。
在unpark之后會(huì)檢測(cè)中斷狀態(tài)拋出異常。這都是在獲取鎖的過程中最大努力的處理中斷咳榜,
但還是有延遲夏醉,線程被park住了,即使有中斷也無法拋出涌韩。acquireQueued也可以完全設(shè)置的和doAcquireInterruptibly參數(shù)
返回值都一樣畔柔,acquireQueued只是為了方便重用。同樣都用try finally 取消線程(或者說設(shè)置線程的取消狀態(tài))臣樱。其他流程都和acquireQueued一樣靶擦。**
/**
請(qǐng)求這個(gè)鎖并立即返回。如果當(dāng)前鎖未被其他線程持有返回true擎淤,否則false奢啥。
注意:即使構(gòu)造ReentrantLock時(shí)設(shè)置公平狀態(tài)為公平鎖,tryLcok仍然是調(diào)用的非公平的嘴拢。
這個(gè)行為在某些情況下非常用于桩盲,即使你使用了公平鎖,仍然可以不判斷隊(duì)列狀態(tài)席吴,嘗試獲取鎖赌结,只要當(dāng)前鎖CAS嘗試修改狀態(tài)成功。
**/
//#ReentrantLock#tryLock
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
/**
獲取鎖如果在給定的等待時(shí)間內(nèi)孝冒,并且當(dāng)前線程沒有被中斷
如果ReentrantLock已經(jīng)被設(shè)置為公平模式柬姚,那么這個(gè)方法必須遵守排隊(duì)策略。這個(gè)是和tryLock方法相反的庄涡。
可以像下面這樣使用組合非公平和公平鎖同時(shí)利用兩種鎖的優(yōu)點(diǎn):
if(lock.tryLock() || lock.tryLock(timeout,unit)){
}
和不帶參數(shù)的tryLock比較:
tryLock(): 非公平鎖 立即返回 可檢測(cè)中斷
tryLock(timeout,unit):公平 (超時(shí))等待阻塞 可檢測(cè)中斷
**/
//#ReentrantLock#tryLock(long timeout, TimeUnit unit)
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
排他模式下使用量承,可響應(yīng)中斷,超時(shí)失敗返回false穴店。
也是首先檢查中斷狀態(tài)撕捍,然后調(diào)用至少一次的tryAquire,成功就直接返回泣洞。否則
將排隊(duì)等待忧风,可能重復(fù)的park或者unpark。知道最后調(diào)用tryAquire成功球凰,或者中斷狮腿、超時(shí)腿宰。
第一個(gè)參數(shù)值是 :aquire的數(shù)量 第二個(gè)參數(shù)值是:等待的納秒
返回true:tryAquire成功,false:超時(shí)
**/
//#AQS#tryAcquireNanos
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
//首先檢測(cè)中斷狀態(tài)
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
/**
排他模式下超時(shí)方法使用
**/
//#AQS#doAcquireNanos
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)//時(shí)間<=0 直接返回false缘厢,即失敗
return false;
final long deadline = System.nanoTime() + nanosTimeout;//等待截止時(shí)間
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L) //等待時(shí)間到了直接返回false
return false;
//可以這么理解截止時(shí)間減去第一次嘗試tryAquire的時(shí)間=剩下的時(shí)間<自旋閥值的話將一直自旋吃度,否則剩下的時(shí)間將park住。
//然后自己醒來昧绣,再判斷中斷狀態(tài)规肴,再進(jìn)行嘗試獲取鎖捶闸,最后重新判斷剩余時(shí)間<=0 返回false.
//返回false之后因?yàn)閒ailed=true夜畴,執(zhí)行cancelAcquire,取消節(jié)點(diǎn)删壮。
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed) //這里的cancelAquire需要處理兩種情況的異常: 1.返回false贪绘,即超時(shí),可認(rèn)為超時(shí)也是一種異常央碟。2.中斷 cancelAquire流程見前面分析:cancelAcquire
cancelAcquire(node);
}
}
######總結(jié):doAcquireNanos 通過spinForTimeoutThreshold税灌,自己進(jìn)入等待,防止傳入等待時(shí)間過長(zhǎng)亿虽,自旋時(shí)間太長(zhǎng)菱涤,過多浪費(fèi)CPU資源,限制了最長(zhǎng)自旋時(shí)間不超過1000納秒洛勉。LockSupport.parkNanos(this, nanosTimeout);則讓線程在隨后的時(shí)間睡眠粘秆,直到給定的時(shí)間,自動(dòng)喚醒自己收毫。當(dāng)然也可以被頭節(jié)點(diǎn)喚醒攻走。無論被誰喚醒線程被unblock后.首先檢查下中斷狀態(tài),然后判斷下是否是head節(jié)點(diǎn)此再,截止獲取下鎖昔搂。如果不成功則,就超時(shí)输拇。所以即便線程超時(shí)他還是有最后一次機(jī)會(huì)去證明自己摘符。
/**
查詢是否有任何線程在排隊(duì)等待獲取鎖。
注意:因?yàn)槿∠赡馨l(fā)生在任何時(shí)候策吠,返回true并不保證任何其他線程將一定獲取到這個(gè)鎖逛裤。
這個(gè)方法主要被設(shè)計(jì)用來監(jiān)控系統(tǒng)的狀態(tài)。
**/
//#ReentrantLock#hasQueuedThreads
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
只是判斷頭結(jié)點(diǎn)不等于尾節(jié)點(diǎn)奴曙。
**/
//#AQS#hasQueuedThreads
public final boolean hasQueuedThreads() {
return head != tail;
}
/**
給定一個(gè)線程判斷他是否在隊(duì)列中等待獲取鎖别凹。
注意:取消可能發(fā)生在任何時(shí)候,返回true洽糟,不保證這個(gè)線程將一定獲取到這個(gè)鎖炉菲。
這個(gè)方法主要被設(shè)計(jì)用來監(jiān)控系統(tǒng)的狀態(tài)堕战。
**/
//#ReentrantLock#hasQueuedThread
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
/**
從后向前遍歷找到這個(gè)線程,找到返回true拍霜,未找到返回false嘱丢。
**/
//AQS#isQueued
public final boolean isQueued(Thread thread) {
if (thread == null)
throw new NullPointerException();
for (Node p = tail; p != null; p = p.prev)
if (p.thread == thread)
return true;
return false;
}
#### AQS和ReentrantLock (公平鎖和非公平鎖部分)的總結(jié):
AQS做的事情是管理隊(duì)列,然后提供一些監(jiān)控方法祠饺,子類只需要實(shí)現(xiàn) protected 標(biāo)記未exclusive的方法,其中有關(guān)獨(dú)占模式的AQS中最重要的管理隊(duì)列的方法:
- 實(shí)現(xiàn)AQS核心算法排隊(duì)自旋有關(guān):
acquireQueued:提供最基本的鎖獲取方式越驻。
doAcquireInterruptibly:在acquireQueued中增加可響應(yīng)中斷
doAcquireNanos:在doAcquireInterruptibly的基礎(chǔ)上增加可設(shè)置超時(shí)
acquire**類方法一般形如如下模板:
try{
for(;;;){
//判斷是否頭節(jié)點(diǎn)&&tryAcquire成功{設(shè)置頭節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn),前頭節(jié)點(diǎn)出隊(duì)道偷,最后返回成功}
//判斷是否需要park
//park
//超時(shí)處理
//中斷處理
}
}finally{
if(failed)
cannelAcquire;
}
shouldParkAfterFailedAcquire:節(jié)點(diǎn)狀態(tài)是實(shí)現(xiàn)前驅(qū)節(jié)點(diǎn)喚醒后驅(qū)節(jié)點(diǎn)設(shè)置狀態(tài)為Node.SIGNAL的唯一地方其他方法中也可以設(shè)置如cancelAcquire缀旁,但是不保證成功。
unparkSuccessor:根據(jù)shouldParkAfterFailedAcquire設(shè)置的waitStatus來喚醒后驅(qū)節(jié)點(diǎn)
release:釋放鎖(修改狀態(tài))勺鸦,可能調(diào)用unparkSuccessor并巍。
- 管理隊(duì)列性能、優(yōu)化相關(guān):
cancelAcquire:取消無效節(jié)點(diǎn)换途,設(shè)置狀態(tài)為Node.CANCELLED
shouldParkAfterFailedAcquire:也會(huì)清除被取消的節(jié)點(diǎn)
unparkSuccessor:也會(huì)清除被取消的節(jié)點(diǎn)
-原始隊(duì)列原子操作相關(guān):
enq懊渡、addWaiter
- 監(jiān)控相關(guān):
hasQueuedThreads、hasQueuedThread
子類只需要實(shí)現(xiàn):
tryAcquire():通過setState军拟、getState設(shè)置修改狀態(tài)
release():子類可能不叫releas叫 unlock剃执,同樣也是設(shè)置狀態(tài),
- 公平非公平鎖實(shí)現(xiàn)相關(guān):
hasQueuedPredecessors:獲取隊(duì)列中是否有比自己排隊(duì)更久的節(jié)點(diǎn)懈息。