java并發(fā)-ReentrantLock的lock和lockInterruptibly的區(qū)別

ReentrantLock的加鎖方法Lock()提供了無條件地輪詢獲取鎖的方式,lockInterruptibly()提供了可中斷的鎖獲取方式。這兩個方法的區(qū)別在哪里呢?通過分析源碼可以知道lock方法默認(rèn)處理了中斷請求,一旦監(jiān)測到中斷狀態(tài),則中斷當(dāng)前線程;而lockInterruptibly()則直接拋出中斷異常,由上層調(diào)用者區(qū)去處理中斷。

1 ?lock操作

? ? ? ?? lock獲取鎖過程中,忽略了中斷,在成功獲取鎖之后,再根據(jù)中斷標(biāo)識處理中斷,即selfInterrupt中斷自己。 acquire操作源碼如下:

/**

??*默認(rèn)處理中斷方式是selfInterrupt

?*/??

public?final?void?acquire(int?arg)?{??

if?(!tryAcquire(arg)?&&??

????????acquireQueued(addWaiter(Node.EXCLUSIVE),?arg))??

????????selfInterrupt();??

}??

? ? ? acquireQueued,在for循環(huán)中無條件重試獲取鎖,直到成功獲取鎖,同時返回線程中斷狀態(tài)。該方法通過for循正常返回時,必定是成功獲取到了鎖。

/**

?*無條件重試,直到成功返回,并且記錄中斷狀態(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);??

????}??

}??

2 lockInterruptibly操作

? ? ?可中斷加鎖,即在鎖獲取過程中不處理中斷狀態(tài),而是直接拋出中斷異常,由上層調(diào)用者處理中斷。源碼細(xì)微差別在于鎖獲取這部分代碼,這個方法與acquireQueue差別在于方法的返回途徑有兩種,一種是for循環(huán)結(jié)束,正常獲取到鎖;另一種是線程被喚醒后檢測到中斷請求,則立即拋出中斷異常,該操作導(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ū)別在于:線程嘗試獲取鎖操作失敗后,在等待過程中,如果該線程被其他線程中斷了,它是如何響應(yīng)中斷請求的。lock方法會忽略中斷請求,繼續(xù)獲取鎖直到成功;而lockInterruptibly則直接拋出中斷異常來立即響應(yīng)中斷,由上層調(diào)用者處理中斷。

? ? ?那么,為什么要分為這兩種模式呢?這兩種加鎖方式分別適用于什么場合呢?根據(jù)它們的實現(xiàn)語義來理解,我認(rèn)為lock()適用于鎖獲取操作不受中斷影響的情況,此時可以忽略中斷請求正常執(zhí)行加鎖操作,因為該操作僅僅記錄了中斷狀態(tài)(通過Thread.currentThread().interrupt()操作,只是恢復(fù)了中斷狀態(tài)為true,并沒有對中斷進(jìn)行響應(yīng))。如果要求被中斷線程不能參與鎖的競爭操作,則此時應(yīng)該使用lockInterruptibly方法,一旦檢測到中斷請求,立即返回不再參與鎖的競爭并且取消鎖獲取操作(即finally中的cancelAcquire操作)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容