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。现在让我们看看以下场景:
账户
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
}
}
添加回答
举报