public class classa {
private int id;
private string name;
private classb b;
// ...
public void m2(){
synchronized(this){
// do something
}
b.method1();
}
// ... ...
}
这样的话减小了锁定的范围,两个锁的申请就没有发生交叉,避免了死锁的可能性,这是最理性的情况,因为锁没有发生交叉。但是有时是不允许我们这样做的。此时,如果只有classa中只有一个m1这样的方法,需要同时获得两个对象上的锁,并且不会将实例属性 b 溢出(return b;),而是将实例属性 b 封闭在对象中,那么也不会发生死锁。因为无法形成死锁的闭环。但是如果classa中有多个方法需要同时获得两个对象上的锁,那么这些方法就必须以相同的顺序获得锁。
比如银行转账的场景下,我们必须同时获得两个账户上的锁,才能进行操作,两个锁的申请必须发生交叉。这时我们也可以打破死锁的那个闭环,在涉及到要同时申请两个锁的方法中,总是以相同的顺序来申请锁,比如总是先申请 id 大的账户上的锁 ,然后再申请 id 小的账户上的锁,这样就无法形成导致死锁的那个闭环。
public class account {
private int id; // 主键
private string name;
private double balance;
public void transfer(account from, account to, double money){
if(from.getid() > to.getid()){
synchronized(from){
synchronized(to){
// transfer
}
}
}else{
synchronized(to){
synchronized(from){
// transfer
}
}
}
}
public int getid() {
return id;
}
}