ReentrantLock的加鎖方法Lock()提供了無(wú)條件地輪詢獲取鎖的方式壳贪,lockInterruptibly()提供了可中斷的鎖獲取方式密末。這兩個(gè)方法的區(qū)別在哪里呢告希?通過(guò)分析源碼可以知道lock方法默認(rèn)處理了中斷請(qǐng)求樟凄,一旦監(jiān)測(cè)到中斷狀態(tài),則中斷當(dāng)前線程薄坏;而lockInterruptibly()則直接拋出中斷異常趋厉,由上層調(diào)用者區(qū)去處理中斷。
? ? ? ?? lock獲取鎖過(guò)程中胶坠,忽略了中斷君账,在成功獲取鎖之后,再根據(jù)中斷標(biāo)識(shí)處理中斷涵但,即selfInterrupt中斷自己。 acquire操作源碼如下:
/**
??*默認(rèn)處理中斷方式是selfInterrupt
?*/??
public?final?void?acquire(int?arg)?{??
if?(!tryAcquire(arg)?&&??
????????acquireQueued(addWaiter(Node.EXCLUSIVE),?arg))??
????????selfInterrupt();??
}??
? ? ? acquireQueued帖蔓,在for循環(huán)中無(wú)條件重試獲取鎖矮瘟,直到成功獲取鎖,同時(shí)返回線程中斷狀態(tài)塑娇。該方法通過(guò)for循正常返回時(shí)澈侠,必定是成功獲取到了鎖。
/**
?*無(wú)條件重試,直到成功返回埋酬,并且記錄中斷狀態(tài)
?*/??
final?boolean?acquireQueued(final?Node?node,?int?arg)?{??
boolean?failed?=?true;??
try?{??
boolean?interrupted?=?false;??
for?(;;)?{??
final?Node?p?=?node.predecessor();??
if?(p?==?head?&&?tryAcquire(arg))?{??
????????????????setHead(node);??
p.next?=null;?//?help?GC??
failed?=false;??
return?interrupted;??
????????????}??
if?(shouldParkAfterFailedAcquire(p,?node)?&&??
????????????????parkAndCheckInterrupt())??
interrupted?=true;??
????????}??
}finally?{??
if?(failed)??
????????????cancelAcquire(node);??
????}??
}??
? ? ?可中斷加鎖哨啃,即在鎖獲取過(guò)程中不處理中斷狀態(tài)烧栋,而是直接拋出中斷異常,由上層調(diào)用者處理中斷拳球。源碼細(xì)微差別在于鎖獲取這部分代碼审姓,這個(gè)方法與acquireQueue差別在于方法的返回途徑有兩種,一種是for循環(huán)結(jié)束祝峻,正常獲取到鎖魔吐;另一種是線程被喚醒后檢測(cè)到中斷請(qǐng)求,則立即拋出中斷異常莱找,該操作導(dǎo)致方法結(jié)束酬姆。
/**
?????*?Acquires?in?exclusive?interruptible?mode.
?????*?@param?arg?the?acquire?argument
?????*/??
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())??
throw?new?InterruptedException();??
????????????}??
}finally?{??
if?(failed)??
????????????????cancelAcquire(node);??
????????}??
????}??
? ? ?結(jié)論:ReentrantLock的中斷和非中斷加鎖模式的區(qū)別在于:線程嘗試獲取鎖操作失敗后,在等待過(guò)程中奥溺,如果該線程被其他線程中斷了辞色,它是如何響應(yīng)中斷請(qǐng)求的。lock方法會(huì)忽略中斷請(qǐng)求浮定,繼續(xù)獲取鎖直到成功相满;而lockInterruptibly則直接拋出中斷異常來(lái)立即響應(yīng)中斷,由上層調(diào)用者處理中斷壶唤。
? ? ?那么雳灵,為什么要分為這兩種模式呢?這兩種加鎖方式分別適用于什么場(chǎng)合呢闸盔?根據(jù)它們的實(shí)現(xiàn)語(yǔ)義來(lái)理解悯辙,我認(rèn)為lock()適用于鎖獲取操作不受中斷影響的情況,此時(shí)可以忽略中斷請(qǐng)求正常執(zhí)行加鎖操作迎吵,因?yàn)樵摬僮鲀H僅記錄了中斷狀態(tài)(通過(guò)Thread.currentThread().interrupt()操作躲撰,只是恢復(fù)了中斷狀態(tài)為true,并沒有對(duì)中斷進(jìn)行響應(yīng))击费。如果要求被中斷線程不能參與鎖的競(jìng)爭(zhēng)操作拢蛋,則此時(shí)應(yīng)該使用lockInterruptibly方法,一旦檢測(cè)到中斷請(qǐng)求蔫巩,立即返回不再參與鎖的競(jìng)爭(zhēng)并且取消鎖獲取操作(即finally中的cancelAcquire操作)