一扰魂、鷸蚌相爭(zhēng):死鎖
如果兩個(gè)或更多個(gè)線程因相互等待對(duì)方而被永遠(yuǎn)暫停劝评,那我們就稱這些線程產(chǎn)生了死鎖
死鎖的檢測(cè):哲學(xué)家就餐問(wèn)題
死鎖產(chǎn)生的條件:
a蒋畜、資源互斥:每個(gè)資源一次只能夠一個(gè)線程使用
b撞叽、資源不可搶奪:涉及的資源只能夠被其持有者線程主動(dòng)釋放,而無(wú)法被
資源持有者和申請(qǐng)者之外的第三方線程所搶奪
c科展、占用并等待資源:涉及的線程至少持有一個(gè)資源并申請(qǐng)其他資源B,而B(niǎo)恰好被其他線程持有
d才睹、循環(huán)等待資源:涉及到的線程必須在等待別的線程持有的資源琅攘,而別的線程又反過(guò)來(lái)等待第一個(gè)線程所持有的資源
條件與死鎖關(guān)系:必要非充分條件:產(chǎn)生死鎖一定滿足上述條件松邪,但滿足上述條件不一定是死鎖
規(guī)避死鎖的方法
a、粗鎖法:使用粗粒度鎖代替多個(gè)鎖
b置济、鎖排序法:相關(guān)線程使用全局統(tǒng)一的順序申請(qǐng)鎖
c、使用ReentrantLock.tryLock(Long护盈, TimeUnit)申請(qǐng)鎖
A線程持有一個(gè)鎖的情況下調(diào)用外部分方法羞酗,而外部方法申請(qǐng)持有線程A的同步鎖方法檀轨;則會(huì)造成死鎖
d、開(kāi)放調(diào)用:一個(gè)方法在調(diào)用外部方法(包括其他類的方法以及當(dāng)前類的可覆蓋方法)的時(shí)候不持有任何鎖
e卫枝、鎖的替代品:無(wú)狀態(tài)對(duì)象讹挎、線程特有對(duì)象筒溃、volatile關(guān)鍵字等
二、沉睡不醒的睡美人:鎖死
a浑测、信號(hào)丟失鎖死:沒(méi)有相應(yīng)的通知線程來(lái)喚醒等待線程而使等待線程一直處于等待狀態(tài)
b歪玲、嵌套監(jiān)視器鎖死:嵌套鎖導(dǎo)致等待線程永遠(yuǎn)無(wú)法被喚醒
代碼例子:
private finalBlockingQueuequeue=newArrayBlockingQueue(10);
private int
processed=0;
private int
accepted=0;
public static void
main(String[] args)throwsInterruptedException{
NestedMonitorLockoutDemo demo =
newNestedMonitorLockoutDemo();
demo.start();
int
i=0;
while
(i-- <100000){
demo.accept(
"message"+ i);
}
}
privatesynchronized voidaccept(Stringmessage)throwsInterruptedException{
queue.put(message);//不要在臨界區(qū)調(diào)用BlockingQueue的阻塞方法漱贱,會(huì)導(dǎo)致嵌套監(jiān)視器鎖死accepted++;
}
privatesynchronized voiddoProcess()throwsInterruptedException {
String msg =
queue.take();//不要在臨界區(qū)調(diào)用BlockingQueue的阻塞方法夭委,會(huì)導(dǎo)致嵌套監(jiān)視器鎖死System.out.print("Process:"+ msg);
processed++;
}
privatevoidstart(){
newWorkerThread().start();
}
classWorkerThreadextendsThread{
@Override
publicvoidrun(){
try{
while(true){
doProcess()
;
}
}
catch(InterruptedException e) {
e.printStackTrace()
;
}
}
}
}
三募强、巧婦難為無(wú)米之炊:線程饑餓
線程一直無(wú)法獲得其所需資源而導(dǎo)致其任務(wù)一直無(wú)法進(jìn)展
典型例子:在高爭(zhēng)用環(huán)境下使用非公平模式的讀寫鎖
四、屢戰(zhàn)屢敗令境,屢敗屢戰(zhàn):活鎖
線程一直處于運(yùn)行狀態(tài)讹开,但其任務(wù)一直無(wú)法進(jìn)展