1 回答

TA貢獻1851條經驗 獲得超5個贊
考慮一家擁有數千個類型的銀行賬戶的銀行Account。現在讓我們看看為什么這段代碼會導致死鎖:
public void transfer(Account a,Account b,int amount)
{
synchronized(a)
{
a.withdraw(amount);
System.out.print(amount+" is withdrawn from account a\n");
try{Thread.sleep(500);}
catch(Exception e){System.out.println(e);}
synchronized(b)
{
b.deposit(amount);
System.out.print(amount+" is deposited into account b\n");
}
}
}
讓有線程tA
和線程tB
。如果線程在線程同時運行時tA
運行以下代碼 ,則可能會出現死鎖,因為如果我們查看以下順序:transfer(accountA, AccountB)
tB
transfer(accountB, accountA)
面向:
synchronized(accountA)
待定:
synchronized(accountB)
tA:嘗試鎖定對象
AccountB
,但鎖定由 tB 持有 =>死鎖
我們看到兩者之間存在循環依賴關系,不允許其中一個線程繼續前進。
如果我們查看您更新的代碼:
public void transfer(Account a,Account b,int amount)
{
synchronized(a)
{
a.withdraw(amount);
System.out.print(amount+" is withdrawn from account a\n");
try{Thread.sleep(500);}
catch(Exception e){System.out.println(e);}
}
synchronized(b)
{
b.deposit(amount);
System.out.print(amount+" is deposited into account b\n");
}
}
我們必須采取以下假設:
賬戶 a 有無限的資金,因為它可能是 a.balance < amount,這意味著 a.balance < 0,這打破了我們總是有余額 >=0 的不變量。
我們允許不一致,例如,如果我們想匯總所有當前現金,我們將匯總少于實際金額,因為您當前的代碼允許我們這樣做。
如果我們嘗試修復代碼,我們必須在更新余額之前確保 a.balance >= amount?,F在讓我們看看以下場景:
賬戶
a
有balance < amount
我們必須等到
a.balance >= amount
從帳戶中取款a
因為我們在這個線程中保持 Account 的鎖
a
,所以沒有其他線程可以更新a.balance
=> 我們遭受饑餓
要解決這些問題,您要么必須使用監視器或條件來檢查 a.balance>=amount 是否要進行,并將線程置于阻塞狀態,以便線程可以進行或更新您的代碼,以便鎖定總是以相同的順序獲取。
解決方案#1:獲取對象鎖的唯一順序
如果我們使用唯一的順序獲取對象的鎖,我們可以確保不會發生死鎖,因為我們以指定的順序獲取鎖,不允許任何循環依賴,否則稱為死鎖。
public void transfer(Account a,Account b,int amount)
{
//define a specific order, in which locks are acquired
//the id's of all accounts are unique!
if(a.id<b.id){
synchronized(a){
synchronized(b){
//do operations here
}
}
}else{
synchronized(b){
synchronized(a){
//do operations here
}
}
}
}
解決方案 #2:使用生產者-消費者模式來檢查a.balance>=amount.
public void transfer(Account a,Account b,int amount)
{
while(true){
synchronized(a){
if(a.balance>=amount){
//do operations here
}
}
try{Thread.sleep(500);} //Use this as a backoff, as otherwise you'd likely get high congestion
catch(Exception e){System.out.println(e);}
}
synchronized(b)
{
//do operations here
}
}
添加回答
舉報